diff options
57 files changed, 689 insertions, 529 deletions
diff --git a/CHANGELOG b/CHANGELOG index 6ae1f8cbcde..53aa970d45c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.3.0 (unreleased) + - API support for starred projects for authorized user (Zeger-Jan van de Weg) + - Add open_issues_count to project API (Stan Hu) - Expand character set of usernames created by Omniauth (Corey Hinshaw) - Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg) - Merge when build succeeds (Zeger-Jan van de Weg) @@ -215,7 +215,7 @@ group :development do gem "annotate", "~> 2.6.0" gem "letter_opener", '~> 1.1.2' gem 'quiet_assets', '~> 1.0.2' - gem 'rerun', '~> 0.10.0' + gem 'rerun', '~> 0.11.0' gem 'bullet', require: false gem 'rblineprof', platform: :mri, require: false gem 'web-console', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 796c90573cc..9799e605db7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,23 +117,6 @@ GEM activemodel (>= 3.2.0) activesupport (>= 3.2.0) json (>= 1.7) - celluloid (0.17.2) - celluloid-essentials - celluloid-extras - celluloid-fsm - celluloid-pool - celluloid-supervision - timers (>= 4.1.1) - celluloid-essentials (0.20.5) - timers (>= 4.1.1) - celluloid-extras (0.20.5) - timers (>= 4.1.1) - celluloid-fsm (0.20.5) - timers (>= 4.1.1) - celluloid-pool (0.20.5) - timers (>= 4.1.1) - celluloid-supervision (0.20.5) - timers (>= 4.1.1) charlock_holmes (0.7.3) chunky_png (1.3.5) cliver (0.3.2) @@ -369,7 +352,6 @@ GEM hipchat (1.5.2) httparty mimemagic - hitimes (1.2.3) html-pipeline (1.11.0) activesupport (>= 2) nokogiri (~> 1.4) @@ -410,8 +392,7 @@ GEM addressable (~> 2.3) letter_opener (1.1.2) launchy (~> 2.2) - listen (2.9.0) - celluloid (>= 0.15.2) + listen (3.0.5) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) loofah (2.0.3) @@ -601,8 +582,8 @@ GEM redis-store (1.1.7) redis (>= 2.2) request_store (1.2.1) - rerun (0.10.0) - listen (~> 2.7, >= 2.7.3) + rerun (0.11.0) + listen (~> 3.0) responders (2.1.0) railties (>= 4.2.0, < 5) rest-client (1.8.0) @@ -759,8 +740,6 @@ GEM thor (0.19.1) thread_safe (0.3.5) tilt (1.4.1) - timers (4.1.1) - hitimes timfel-krb5-auth (0.8.3) tinder (1.10.1) eventmachine (~> 1.0) @@ -941,7 +920,7 @@ DEPENDENCIES redis-namespace redis-rails (~> 4.0.0) request_store (~> 1.2.0) - rerun (~> 0.10.0) + rerun (~> 0.11.0) responders (~> 2.0) rouge (~> 1.10.1) rqrcode-rails3 (~> 0.1.7) diff --git a/app/assets/javascripts/issuable_context.js.coffee b/app/assets/javascripts/issuable_context.js.coffee index 01bd515cc02..02232698bc2 100644 --- a/app/assets/javascripts/issuable_context.js.coffee +++ b/app/assets/javascripts/issuable_context.js.coffee @@ -18,7 +18,7 @@ class @IssuableContext $('.issuable-affix').affix offset: top: -> - @top = ($('.issuable-affix').offset().top - 60) + @top = ($('.issuable-affix').offset().top - 70) bottom: -> @bottom = $('.footer').outerHeight(true) diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index 603a16da1ce..eff80bf63bb 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -10,12 +10,12 @@ class @Issue @initTaskList() initTaskList: -> - $('.issue-details .js-task-list-container').taskList('enable') - $(document).on 'tasklist:changed', '.issue-details .js-task-list-container', @updateTaskList + $('.detail-page-description .js-task-list-container').taskList('enable') + $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList disableTaskList: -> - $('.issue-details .js-task-list-container').taskList('disable') - $(document).off 'tasklist:changed', '.issue-details .js-task-list-container' + $('.detail-page-description .js-task-list-container').taskList('disable') + $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container' # TODO (rspeicher): Make the issue description inline-editable like a note so # that we can re-use its form here diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index b21cb7904b5..9047587db81 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -40,12 +40,12 @@ class @MergeRequest this.$('.all-commits').removeClass 'hide' initTaskList: -> - $('.merge-request-details .js-task-list-container').taskList('enable') - $(document).on 'tasklist:changed', '.merge-request-details .js-task-list-container', @updateTaskList + $('.detail-page-description .js-task-list-container').taskList('enable') + $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList disableTaskList: -> - $('.merge-request-details .js-task-list-container').taskList('disable') - $(document).off 'tasklist:changed', '.merge-request-details .js-task-list-container' + $('.detail-page-description .js-task-list-container').taskList('disable') + $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container' # TODO (rspeicher): Make the merge request description inline-editable like a # note so that we can re-use its form here diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 2348579e886..bc38a25c6c8 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -183,7 +183,3 @@ .btn-clipboard { border: none; } - -.label_btn { - padding: 8px -} diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss index 24b25aca38f..ee36935dcf5 100644 --- a/app/assets/stylesheets/framework/issue_box.scss +++ b/app/assets/stylesheets/framework/issue_box.scss @@ -14,22 +14,22 @@ margin-right: 10px; font-size: $gl-font-size; - &.issue-box-closed { + &.status-box-closed { background-color: $gl-danger; color: #FFF; } - &.issue-box-merged { + &.status-box-merged { background-color: $gl-primary; color: #FFF; } - + &.issue-box-open { background-color: #31af64; color: #FFF; } - &.issue-box-expired { + &.status-box-expired { background: #cea61b; color: #FFF; } diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index cc48f8c8166..1c74e525a60 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -143,7 +143,11 @@ ul.controls { > li { float: left; - padding-right: 10px; + margin-right: 10px; + + &:last-child { + margin-right: 0; + } .author_link { display: inline-block; diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 2b044786738..4a00a197d9a 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -87,7 +87,7 @@ .new_note, .edit_note, -.issuable-description, +.detail-page-description, .milestone-description, .wiki-content, .merge-request-form { diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss index 57b9451b264..b1a75434499 100644 --- a/app/assets/stylesheets/framework/panels.scss +++ b/app/assets/stylesheets/framework/panels.scss @@ -2,7 +2,8 @@ margin-bottom: $gl-padding; .panel-heading { - padding: 7px $gl-padding; + padding: 12px 0; + margin: 0 $gl-padding; } .panel-body { diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index eb53c4153d3..ff41e26ed8a 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -10,8 +10,7 @@ margin-left: -$gl-padding; margin-right: -$gl-padding; color: $gl-gray; - border-bottom: 1px solid #ECEEF1; - border-right: 1px solid #ECEEF1; + border-bottom: 1px solid $border-white-light; &:target { background: $hover; diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss index 35067a2084a..32793340f1a 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap.scss @@ -218,12 +218,36 @@ } .panel-success { + background-color: $green-normal; .panel-body { - background-color: #2faa60; color: #fff; } + .panel-heading { + border-bottom: 1px solid #289957; + } +} + +.panel-info { + background-color: $blue-normal; + .panel-body { + color: #fff; + } + .panel-heading { + border-bottom: 1px solid #2b8dbe; + } } +.panel-primary { + background-color: $blue-normal; + .panel-body { + color: #fff; + } + .panel-heading { + border-bottom: 1px solid #2b8dbe; + } +} + + .alert-help { background-color: $background-color; border: 1px solid $border-color; diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss new file mode 100644 index 00000000000..0f3463a9144 --- /dev/null +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -0,0 +1,33 @@ +.detail-page-header { + margin: -$gl-padding; + padding: 7px $gl-padding; + margin-bottom: 0px; + border-bottom: 1px solid $border-color; + color: #5c5d5e; + font-size: 16px; + line-height: 42px; + + .author { + color: #5c5d5e; + } + + .identifier { + color: #5c5d5e; + } +} + +.detail-page-description { + .title { + margin: 0; + font-size: 23px; + color: #313236; + } + + .description { + margin-top: 6px; + + p:last-child { + margin-bottom: 0; + } + } +} diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 69d1c0b68d5..eada7c97d30 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -18,7 +18,7 @@ &.affix { position: fixed; - top: 60px; + top: 70px; margin-right: 35px; } } @@ -36,33 +36,12 @@ } .issuable-details { - .issue-title { - margin: 0; - font-size: 23px; - color: #313236; - } - - .description { - margin-top: 6px; - - p:last-child { - margin-bottom: 0; - } - } - section { - border-right: 1px solid #ECEEF1; + border-right: 1px solid $border-white-light; - > .tab-content { + .issuable-discussion { margin-right: 1px; } - - .issue-discussion > .gray-content-block, - > .gray-content-block { - margin-top: 0; - border-top: none; - margin-right: -15px; - } } } @@ -135,24 +114,4 @@ margin-top: 6px; margin-right: 2px; } -} - -.issuable-title { - margin: -$gl-padding; - padding: 10px $gl-padding; - margin-bottom: 0px; - border-bottom: 1px solid $border-color; - color: #8F8F8F; - font-size: 16px; - line-height: 34px; - - .author { - color: #323232; - font-weight: 500; - } - - .issuable-id { - color: #323232; - font-weight: 500; - } -} +}
\ No newline at end of file diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index a652b65502f..a02a3a72e79 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -141,11 +141,6 @@ form.edit-issue { } } -.issue-closed-by-widget { - padding: 16px 0; - margin: 0px; -} - .issue-form .select2-container { width: 250px !important; } diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index d8ebd226237..18cfcc05e7b 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -79,7 +79,6 @@ padding: $gl-padding; margin-left: -$gl-padding; margin-right: -$gl-padding; - border-right: 1px solid $border-color; border-top: 1px solid $border-color; margin-bottom: -$gl-padding; } diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss index a7d3b2197f1..4b6ef035673 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -35,3 +35,20 @@ border-color: $gl-warning; } } + +.ci-status-icon-success { + @extend .cgreen; +} +.ci-status-icon-failed { + @extend .cred; +} +.ci-status-icon-running, +.ci-status-icon-pending { + // These are standard text color +} +.ci-status-icon-canceled, +.ci-status-icon-disabled, +.ci-status-icon-not-found, +.ci-status-icon-skipped { + @extend .cgray; +} diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index fffd90d87eb..ab5c953189c 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -7,7 +7,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds] before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds] before_action :define_show_vars, only: [:show, :diffs, :commits, :builds] - before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds] + before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check] before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds] # Allow read any merge_request @@ -153,11 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def merge_check - if @merge_request.unchecked? - @merge_request.check_if_can_be_merged - end - - closes_issues + @merge_request.check_if_can_be_merged if @merge_request.unchecked? render partial: "projects/merge_requests/widget/show.html.haml", layout: false end @@ -178,7 +174,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.update(merge_error: nil) - if params[:merge_when_build_succeeds] && @merge_request.ci_commit && @merge_request.ci_commit.active? + if params[:merge_when_build_succeeds].present? && @merge_request.ci_commit && @merge_request.ci_commit.active? MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) .execute(@merge_request) @status = :merge_when_build_succeeds @@ -299,6 +295,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController def define_widget_vars @ci_commit = @merge_request.ci_commit + closes_issues end def invalid_mr diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 8554074d619..d8bee21c82e 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -12,19 +12,6 @@ module CiStatusHelper ci_label_for_status(ci_commit.status) end - def ci_status_color(ci_commit) - case ci_commit.status - when 'success' - 'green' - when 'failed' - 'red' - when 'running', 'pending' - 'yellow' - else - 'gray' - end - end - def ci_status_with_icon(status) content_tag :span, class: "ci-status ci-#{status}" do ci_icon_for_status(status) + ' '.html_safe + ci_label_for_status(status) @@ -56,12 +43,11 @@ module CiStatusHelper end def render_ci_status(ci_commit) - link_to ci_status_path(ci_commit), - class: "ci-status-link c#{ci_status_color(ci_commit)}", + link_to ci_status_icon(ci_commit), + ci_status_path(ci_commit), + class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}", title: "Build #{ci_status_label(ci_commit)}", - data: { toggle: 'tooltip', placement: 'left' } do - ci_status_icon(ci_commit) - end + data: { toggle: 'tooltip', placement: 'left' } end def no_runners_for_project?(project) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index cdf7038b2f2..d2186427dba 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -57,15 +57,15 @@ module IssuesHelper options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id) end - def issue_box_class(item) + def status_box_class(item) if item.respond_to?(:expired?) && item.expired? - 'issue-box-expired' + 'status-box-expired' elsif item.respond_to?(:merged?) && item.merged? - 'issue-box-merged' + 'status-box-merged' elsif item.closed? - 'issue-box-closed' + 'status-box-closed' else - 'issue-box-open' + 'status-box-open' end end diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index d4e3099453d..1fdcda97520 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -51,7 +51,7 @@ module Mentionable else self.class.mentionable_attrs.each do |attr, options| text = send(attr) - options[:cache_key] = [self, attr] if options.delete(:cache) + options[:cache_key] = [self, attr] if options.delete(:cache) && self.persisted? ext.analyze(text, options) end end diff --git a/app/models/project.rb b/app/models/project.rb index 87116451caa..13fd383237c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -850,4 +850,8 @@ class Project < ActiveRecord::Base def build_timeout_in_minutes=(value) self.build_timeout = value.to_i * 60 end + + def open_issues_count + issues.opened.count + end end diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml index 44b7efe5232..4316c358dcb 100644 --- a/app/views/dashboard/milestones/show.html.haml +++ b/app/views/dashboard/milestones/show.html.haml @@ -1,18 +1,18 @@ - page_title @milestone.title, "Milestones" - header_title "Milestones", dashboard_milestones_path -.issuable-details - .page-title - .issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" } - - if @milestone.closed? - Closed - - else - Open +.detail-page-header + .status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" } + - if @milestone.closed? + Closed + - else + Open + %span.identifier Milestone #{@milestone.title} - .gray-content-block.middle-block - %h2.issue-title - = markdown escape_once(@milestone.title), pipeline: :single_line +.detail-page-description.gray-content-block.second-block + %h2.title + = markdown escape_once(@milestone.title), pipeline: :single_line - if @milestone.complete? && @milestone.active? .alert.alert-success.prepend-top-default diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index 350e216fcc6..d063b257b5e 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -1,24 +1,24 @@ - page_title @milestone.title, "Milestones" = render "header_title" -.issuable-details - .page-title - .issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" } - - if @milestone.closed? - Closed - - else - Open +.detail-page-header + .status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" } + - if @milestone.closed? + Closed + - else + Open + %span.identifier Milestone #{@milestone.title} - .pull-right - - if can?(current_user, :admin_milestones, @group) - - if @milestone.active? - = link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close" - - else - = link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen" + .pull-right + - if can?(current_user, :admin_milestones, @group) + - if @milestone.active? + = link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close" + - else + = link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen" - .gray-content-block.middle-block - %h2.issue-title - = markdown escape_once(@milestone.title), pipeline: :single_line +.detail-page-description.gray-content-block.second-block + %h2.title + = markdown escape_once(@milestone.title), pipeline: :single_line - if @milestone.complete? && @milestone.active? .alert.alert-success.prepend-top-default diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml index 45a00e4d259..74a05df24d3 100644 --- a/app/views/projects/commit_statuses/_commit_status.html.haml +++ b/app/views/projects/commit_statuses/_commit_status.html.haml @@ -19,11 +19,11 @@ - if defined?(commit_sha) && commit_sha %td - = link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace" - + = link_to commit_status.short_sha, namespace_project_commit_path(commit_status.project.namespace, commit_status.project, commit_status.sha), class: "monospace" + %td - if commit_status.ref - = link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref) + = link_to commit_status.ref, namespace_project_commits_path(commit_status.project.namespace, commit_status.project, commit_status.ref) - else .light none @@ -66,7 +66,7 @@ %td .pull-right - - if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url + - if current_user && can?(current_user, :download_build_artifacts, commit_status.project) && commit_status.download_url = link_to commit_status.download_url, title: 'Download artifacts' do %i.fa.fa-download - if current_user && can?(current_user, :manage_builds, commit_status.project) diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml index 3c491c1a8b8..de415ae51a4 100644 --- a/app/views/projects/issues/_closed_by_box.html.haml +++ b/app/views/projects/issues/_closed_by_box.html.haml @@ -1,3 +1,2 @@ -.issue-closed-by-widget - = icon('check') +.issue-closed-by-widget.gray-content-block.second-block.white This issue will be closed automatically when merge request #{markdown(merge_requests_sentence(@closed_by_merge_requests), pipeline: :gfm)} is accepted. diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index c029d69bb98..64e1912685b 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -5,8 +5,5 @@ - else = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-warning js-note-target-close', title: 'Close Issue' -.gray-content-block.second-block.oneline-block - = render 'votes/votes_block', votable: @issue - #notes = render 'projects/notes/notes_with_form' diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index ec5d2b9d8e1..2fe6f88b2a9 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -2,60 +2,65 @@ = render "header_title" .issue - .issue-details.issuable-details - .issuable-title - .issue-box{ class: issue_box_class(@issue) } + .detail-page-header + .status-box{ class: status_box_class(@issue) } + - if @issue.closed? + Closed + - else + Open + %span.identifier + Issue ##{@issue.iid} + %span.creator + · + opened by #{link_to_member(@project, @issue.author, size: 24)} + · + = time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago') + - if @issue.updated_at != @issue.created_at + %span + · + = icon('edit', title: 'edited') + = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago') + + .pull-right + - if can?(current_user, :create_issue, @project) + = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-grouped new-issue-link', title: 'New Issue', id: 'new_issue_link' do + = icon('plus') + New Issue + - if can?(current_user, :update_issue, @issue) - if @issue.closed? - Closed + = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen' - else - Open - %span.issuable-id Issue ##{@issue.iid} - %span.creator - · - opened by #{link_to_member(@project, @issue.author, size: 24)} - · - = time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago') - - if @issue.updated_at != @issue.created_at - %span - · - = icon('edit', title: 'edited') - = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago') + = link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-close', title: 'Close Issue' - .pull-right - - if can?(current_user, :create_issue, @project) - = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-grouped btn-success', title: 'New Issue', id: 'new_issue_link' do - = icon('plus') - New Issue - - if can?(current_user, :update_issue, @issue) - - if @issue.closed? - = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-default' - - else - = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-warning', title: 'Close Issue' + = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-grouped issuable-edit' do + = icon('pencil-square-o') + Edit - = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-grouped btn-default' do - = icon('pencil-square-o') - Edit + .issue-details.issuable-details + .detail-page-description.gray-content-block.second-block + %h2.title + = markdown escape_once(@issue.title), pipeline: :single_line + %div + - if @issue.description.present? + .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} + .wiki + = preserve do + = markdown(@issue.description, cache_key: [@issue, "description"]) + %textarea.hidden.js-task-list-field + = @issue.description - .row - %section.col-md-9 - .gray-content-block - %h2.issue-title - = markdown escape_once(@issue.title), pipeline: :single_line - %div - - if @issue.description.present? - .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} - .wiki - = preserve do - = markdown(@issue.description, cache_key: [@issue, "description"]) - %textarea.hidden.js-task-list-field - = @issue.description + .merge-requests + = render 'merge_requests' + + .gray-content-block.second-block.oneline-block + = render 'votes/votes_block', votable: @issue - .merge-requests - = render 'merge_requests' + - if @closed_by_merge_requests.present? + = render 'projects/issues/closed_by_box' - - if @closed_by_merge_requests.present? - = render 'projects/issues/closed_by_box' - .issue-discussion + .row + %section.col-md-9 + .issuable-discussion = render 'projects/issues/discussion' %aside.col-md-3 diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index 7a7428d35cc..399e9cc1e1b 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -5,7 +5,4 @@ - if @merge_request.closed? = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" -.gray-content-block.second-block.oneline-block - = render 'votes/votes_block', votable: @merge_request - #notes= render "projects/notes/notes_with_form" diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 4172d5a4e88..a14943b15d3 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -23,15 +23,15 @@ = link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do Commits %span.badge= @commits.size - %li.diffs-tab.active - = link_to url_for(params), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do - Changes - %span.badge= @diffs.size - if @ci_commit %li.builds-tab.active = link_to url_for(params), data: {target: 'div#builds', action: 'builds', toggle: 'tab'} do Builds %span.badge= @statuses.size + %li.diffs-tab.active + = link_to url_for(params), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do + Changes + %span.badge= @diffs.size .tab-content #commits.commits.tab-pane diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 04f8fd74422..e9ffbd06be2 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -5,81 +5,84 @@ - fluid_layout true .merge-request{'data-url' => merge_request_path(@merge_request)} - .merge-request-details.issuable-details - = render "projects/merge_requests/show/mr_title" - .row - %section.col-md-9 - = render "projects/merge_requests/show/mr_box" - .append-bottom-default.mr-source-target.prepend-top-default - - if @merge_request.open? - .pull-right - - if @merge_request.source_branch_exists? - = link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do - = icon('cloud-download fw') - Check out branch + = render "projects/merge_requests/show/mr_title" - %span.dropdown - %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} } - = icon('download') - Download as - %span.caret - %ul.dropdown-menu - %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) - %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) - .normal - %span Request to merge - %span.label-branch= source_branch_with_namespace(@merge_request) - %span into - = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do - = @merge_request.target_branch + .merge-request-details.issuable-details + = render "projects/merge_requests/show/mr_box" + .append-bottom-default.mr-source-target.prepend-top-default + - if @merge_request.open? + .pull-right + - if @merge_request.source_branch_exists? + = link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do + = icon('cloud-download fw') + Check out branch - = render "projects/merge_requests/show/how_to_merge" - = render "projects/merge_requests/widget/show.html.haml" + %span.dropdown + %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} } + = icon('download') + Download as + %span.caret + %ul.dropdown-menu + %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) + %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) + .normal + %span Request to merge + %span.label-branch= source_branch_with_namespace(@merge_request) + %span into + = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do + = @merge_request.target_branch - - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user) - .light.prepend-top-default - You can also accept this merge request manually using the - = succeed '.' do - = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" + = render "projects/merge_requests/show/how_to_merge" + = render "projects/merge_requests/widget/show.html.haml" - - if @commits.present? - %ul.merge-request-tabs.center-top-menu.no-top.no-bottom - %li.notes-tab - = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do - Discussion - %span.badge= @merge_request.mr_and_commit_notes.user.count - %li.commits-tab - = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do - Commits - %span.badge= @commits.size - %li.diffs-tab - = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do - Changes - %span.badge= @merge_request.diffs.size - - if @ci_commit - %li.builds-tab - = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do - Builds - %span.badge= @statuses.size + - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user) + .light.prepend-top-default + You can also accept this merge request manually using the + = succeed '.' do + = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" - .tab-content - #notes.notes.tab-pane.voting_notes - = render "projects/merge_requests/discussion" - #commits.commits.tab-pane - - # This tab is always loaded via AJAX - #diffs.diffs.tab-pane - - # This tab is always loaded via AJAX - #builds.builds.tab-pane - - # This tab is always loaded via AJAX + - if @commits.present? + %ul.merge-request-tabs.center-top-menu.no-top.no-bottom + %li.notes-tab + = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do + Discussion + %span.badge= @merge_request.mr_and_commit_notes.user.count + %li.commits-tab + = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do + Commits + %span.badge= @commits.size + - if @ci_commit + %li.builds-tab + = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do + Builds + %span.badge= @statuses.size + %li.diffs-tab + = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do + Changes + %span.badge= @merge_request.diffs.size - .mr-loading-status - = spinner + .tab-content + #notes.notes.tab-pane.voting_notes + .gray-content-block.second-block.oneline-block + = render 'votes/votes_block', votable: @merge_request - %aside.col-md-3 - = render 'shared/issuable/sidebar', issuable: @merge_request + .row + %section.col-md-9 + .issuable-discussion + = render "projects/merge_requests/discussion" + %aside.col-md-3 + = render 'shared/issuable/sidebar', issuable: @merge_request + = render 'shared/show_aside' - = render 'shared/show_aside' + #commits.commits.tab-pane + - # This tab is always loaded via AJAX + #builds.builds.tab-pane + - # This tab is always loaded via AJAX + #diffs.diffs.tab-pane + - # This tab is always loaded via AJAX + .mr-loading-status + = spinner :javascript var merge_request; diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index 9bfe202589e..0f81e5e8914 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -1,5 +1,5 @@ -.gray-content-block.middle-block - %h2.issue-title +.detail-page-description.gray-content-block.second-block + %h2.title = markdown escape_once(@merge_request.title), pipeline: :single_line %div diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index d65c3b16618..acb207eb1d6 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,7 +1,8 @@ -.issuable-title - .issue-box{ class: issue_box_class(@merge_request) } +.detail-page-header + .status-box{ class: status_box_class(@merge_request) } = @merge_request.state_human_name - %span.issuable-id Merge Request ##{@merge_request.iid} + %span.identifier + Merge Request ##{@merge_request.iid} %span.creator · opened by #{link_to_member(@project, @merge_request.author, size: 24)} diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index c6bc4ca5beb..d9a1730a8bc 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -7,13 +7,13 @@ .accept-action - if @ci_commit && @ci_commit.active? %span.btn-group - = link_to "#", class: "btn btn-create merge_when_build_succeeds" do + = button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do Merge When Build Succeeds - %a.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown' } + = button_tag class: "btn btn-success dropdown-toggle", 'data-toggle' => 'dropdown' do %span.caret %span.sr-only Select Merge Moment - %ul.dropdown-menu.dropdown-menu-right{ role: 'menu' } + %ul.js-merge-dropdown.dropdown-menu.dropdown-menu-right{ role: 'menu' } %li = link_to "#", class: "merge_when_build_succeeds" do = icon('check fw') @@ -23,7 +23,7 @@ = icon('warning fw') Merge Immediately - else - = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do + = f.button class: "btn btn-create btn-grouped js-merge-button accept_merge_request #{status_class}" do Accept Merge Request - if @merge_request.can_remove_source_branch?(current_user) .accept-control.checkbox @@ -42,21 +42,19 @@ = hidden_field_tag :merge_when_build_succeeds, "", autocomplete: "off" :javascript - $('.accept_merge_request').on('click', function() { - $(this).html("<i class='fa fa-spinner fa-spin'></i> Merge in progress"); - }); - $('.accept-mr-form').on('ajax:send', function() { $(".accept-mr-form :input").disable(); }); - $('a.accept_merge_request').on('click', function(e) { - e.preventDefault(); - $(this).closest("form").submit(); + $('.accept_merge_request').on('click', function() { + $('.js-merge-button').html("<i class='fa fa-spinner fa-spin'></i> Merge in progress"); }); - $('a.merge_when_build_succeeds').on('click', function(e) { - e.preventDefault(); + $('.merge_when_build_succeeds').on('click', function() { $("#merge_when_build_succeeds").val("1"); + }); + + $('.js-merge-dropdown a').on('click', function(e) { + e.preventDefault(); $(this).closest("form").submit(); }); diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 7ecee440337..7e73ae274e9 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -1,44 +1,44 @@ - page_title @milestone.title, "Milestones" = render "header_title" -.issuable-details - .page-title - .issue-box{ class: issue_box_class(@milestone) } - - if @milestone.closed? - Closed - - elsif @milestone.expired? - Expired - - else - Open +.detail-page-header + .status-box{ class: status_box_class(@milestone) } + - if @milestone.closed? + Closed + - elsif @milestone.expired? + Expired + - else + Open + %span.identifier Milestone ##{@milestone.iid} - - if @milestone.expires_at - %span.creator - · - = @milestone.expires_at - .pull-right - - if can?(current_user, :admin_milestone, @project) - = link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do - %i.fa.fa-pencil-square-o - Edit + - if @milestone.expires_at + %span.creator + · + = @milestone.expires_at + .pull-right + - if can?(current_user, :admin_milestone, @project) + - if @milestone.active? + = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped" + - else + = link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped" - - if @milestone.active? - = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped" - - else - = link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped" + = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do + %i.fa.fa-trash-o + Delete - = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do - %i.fa.fa-trash-o - Delete + = link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do + %i.fa.fa-pencil-square-o + Edit - .gray-content-block.middle-block - %h2.issue-title - = markdown escape_once(@milestone.title), pipeline: :single_line - %div - - if @milestone.description.present? - .description - .wiki - = preserve do - = markdown @milestone.description +.detail-page-description.gray-content-block.second-block + %h2.title + = markdown escape_once(@milestone.title), pipeline: :single_line + %div + - if @milestone.description.present? + .description + .wiki + = preserve do + = markdown @milestone.description - if @milestone.issues.any? && @milestone.can_be_closed? .alert.alert-success.prepend-top-default diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 91ccd1ef660..90dc0062481 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -19,7 +19,7 @@ - else Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a <strong>Work In Progress</strong> merge request from being merged before it's ready. -.form-group.issuable-description +.form-group.detail-page-description = f.label :description, 'Description', class: 'control-label' .col-sm-10 diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 0019f739b89..79c5cc7f40a 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -1,13 +1,5 @@ .issuable-sidebar.issuable-affix = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f| - .block - .title - Cross-project reference - .cross-project-reference - %span#cross-project-reference - = cross_project_reference(@project, issuable) - = clipboard_button(clipboard_target: 'span#cross-project-reference') - .block.assignee .title %label @@ -62,6 +54,14 @@ = f.collection_select :label_ids, issuable.project.labels.all, :id, :name, { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" } + .block + .title + Cross-project reference + .cross-project-reference + %span#cross-project-reference + = cross_project_reference(@project, issuable) + = clipboard_button(clipboard_target: 'span#cross-project-reference') + = render "shared/issuable/participants", participants: issuable.participants(current_user) - if current_user diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml index 669e6119fb6..aa5acee9c14 100644 --- a/app/views/shared/snippets/_header.html.haml +++ b/app/views/shared/snippets/_header.html.haml @@ -1,25 +1,25 @@ -.issuable-details - .page-title - .snippet-box.has_tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }} - = visibility_level_icon(@snippet.visibility_level, fw: false) - = visibility_level_label(@snippet.visibility_level) +.detail-page-header + .snippet-box.has_tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }} + = visibility_level_icon(@snippet.visibility_level, fw: false) + = visibility_level_label(@snippet.visibility_level) + %span.identifier Snippet ##{@snippet.id} - %span.creator - · created by #{link_to_member(@project, @snippet.author, size: 24)} - · - = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago') - - if @snippet.updated_at != @snippet.created_at - %span - · - = icon('edit', title: 'edited') - = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago') + %span.creator + · created by #{link_to_member(@project, @snippet.author, size: 24)} + · + = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago') + - if @snippet.updated_at != @snippet.created_at + %span + · + = icon('edit', title: 'edited') + = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago') - .pull-right - - if @snippet.project_id? - = render "projects/snippets/actions" - - else - = render "snippets/actions" + .pull-right + - if @snippet.project_id? + = render "projects/snippets/actions" + - else + = render "snippets/actions" - .gray-content-block.middle-block - %h2.issue-title - = markdown escape_once(@snippet.title), pipeline: :single_line +.detail-page-description.gray-content-block.second-block + %h2.title + = markdown escape_once(@snippet.title), pipeline: :single_line diff --git a/db/migrate/20151210125930_migrate_ci_to_project.rb b/db/migrate/20151210125930_migrate_ci_to_project.rb index 7dfe05174ee..75278997862 100644 --- a/db/migrate/20151210125930_migrate_ci_to_project.rb +++ b/db/migrate/20151210125930_migrate_ci_to_project.rb @@ -26,7 +26,8 @@ class MigrateCiToProject < ActiveRecord::Migration def migrate_project_column(column, new_column = nil) new_column ||= column - subquery = "SELECT ci_projects.#{column} FROM ci_projects WHERE projects.id = ci_projects.gitlab_id" + subquery = "SELECT ci_projects.#{column} FROM ci_projects WHERE projects.id = ci_projects.gitlab_id " \ + 'ORDER BY ci_projects.updated_at DESC LIMIT 1' execute("UPDATE projects SET #{new_column}=(#{subquery}) WHERE (#{subquery}) IS NOT NULL") end diff --git a/doc/api/projects.md b/doc/api/projects.md index 1a524400627..658e65c6f01 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -58,6 +58,7 @@ Parameters: "path": "diaspora-client", "path_with_namespace": "diaspora/diaspora-client", "issues_enabled": true, + "open_issues_count": 1, "merge_requests_enabled": true, "builds_enabled": true, "wiki_enabled": true, @@ -100,6 +101,7 @@ Parameters: "path": "puppet", "path_with_namespace": "brightbox/puppet", "issues_enabled": true, + "open_issues_count": 1, "merge_requests_enabled": true, "builds_enabled": true, "wiki_enabled": true, @@ -137,6 +139,21 @@ Parameters: - `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc` - `search` (optional) - Return list of authorized projects according to a search criteria +### List starred projects + +Get a list of projects which are starred by the authenticated user. + +``` +GET /projects/starred +``` + +Parameters: + +- `archived` (optional) - if passed, limit by archived status +- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at` +- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc` +- `search` (optional) - Return list of authorized projects according to a search criteria + ### List ALL projects Get a list of all GitLab projects (admin only). @@ -189,6 +206,7 @@ Parameters: "path": "diaspora-project-site", "path_with_namespace": "diaspora/diaspora-project-site", "issues_enabled": true, + "open_issues_count": 1, "merge_requests_enabled": true, "builds_enabled": true, "wiki_enabled": true, diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 8d4bd44053e..31458d61674 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -1,11 +1,11 @@ # Using Docker Images -GitLab CI in conjuction with [GitLab Runner](../runners/README.md) can use +GitLab CI in conjunction with [GitLab Runner](../runners/README.md) can use [Docker Engine](https://www.docker.com/) to test and build any application. Docker is an open-source project that allows you to use predefined images to run applications in independent "containers" that are run within a single Linux -instance. [Docker Hub][hub] has a rich database of prebuilt images that can be +instance. [Docker Hub][hub] has a rich database of pre-built images that can be used to test and build your applications. Docker, when used with GitLab CI, runs each build in a separate and isolated @@ -136,6 +136,24 @@ Look for the `[runners.docker]` section: The image and services defined this way will be added to all builds run by that runner. +## Define an image from a private Docker registry + +Starting with GitLab Runner 0.6.0, you are able to define images located to +private registries that could also require authentication. + +All you have to do is be explicit on the image definition in `.gitlab-ci.yml`. + +```yaml +image: my.registry.tld:5000/namepace/image:tag +``` + +In the example above, GitLab Runner will look at `my.registry.tld:5000` for the +image `namespace/image:tag`. + +If the repository is private you need to authenticate your GitLab Runner in the +registry. Learn how to do that on +[GitLab Runner's documentation][runner-priv-reg]. + ## Accessing the services Let's say that you need a Wordpress instance to test some API integration with @@ -258,3 +276,4 @@ creation. [tutum/wordpress]: https://registry.hub.docker.com/u/tutum/wordpress/ [postgres-hub]: https://registry.hub.docker.com/u/library/postgres/ [mysql-hub]: https://registry.hub.docker.com/u/library/mysql/ +[runner-priv-reg]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#using-a-private-docker-registry diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 7e2edb945da..c5bdce2f778 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1,9 +1,12 @@ # Configuration of your builds with .gitlab-ci.yml -From version 7.12, GitLab CI uses a [YAML](https://en.wikipedia.org/wiki/YAML) file (**.gitlab-ci.yml**) for the project configuration. -It is placed in the root of your repository and contains definitions of how your project should be built. -The YAML file defines a set of jobs with constraints stating when they should be run. -The jobs are defined as top-level elements with a name and always have to contain the `script` clause: +From version 7.12, GitLab CI uses a [YAML](https://en.wikipedia.org/wiki/YAML) +file (`.gitlab-ci.yml`) for the project configuration. It is placed in the root +of your repository and contains definitions of how your project should be built. + +The YAML file defines a set of jobs with constraints stating when they should +be run. The jobs are defined as top-level elements with a name and always have +to contain the `script` clause: ```yaml job1: @@ -13,15 +16,21 @@ job2: script: "execute-script-for-job2" ``` -The above example is the simplest possible CI configuration with two separate jobs, -where each of the jobs executes a different command. -Of course a command can execute code directly (`./configure;make;make install`) or run a script (`test.sh`) in the repository. +The above example is the simplest possible CI configuration with two separate +jobs, where each of the jobs executes a different command. + +Of course a command can execute code directly (`./configure;make;make install`) +or run a script (`test.sh`) in the repository. -Jobs are used to create builds, which are then picked up by [runners](../runners/README.md) and executed within the environment of the runner. -What is important, is that each job is run independently from each other. +Jobs are used to create builds, which are then picked up by +[runners](../runners/README.md) and executed within the environment of the +runner. What is important, is that each job is run independently from each +other. ## .gitlab-ci.yml -The YAML syntax allows for using more complex job specifications than in the above example: + +The YAML syntax allows for using more complex job specifications than in the +above example: ```yaml image: ruby:2.1 @@ -46,26 +55,31 @@ job1: - docker ``` -There are a few `keywords` that can't be used as job names: +There are a few reserved `keywords` that **cannot** be used as job names: -| keyword | required | description | +| Keyword | Required | Description | |---------------|----------|-------------| -| image | optional | Use docker image, covered in [Use Docker](../docker/README.md) | -| services | optional | Use docker services, covered in [Use Docker](../docker/README.md) | -| stages | optional | Define build stages | -| types | optional | Alias for `stages` | -| before_script | optional | Define commands prepended for each job's script | -| variables | optional | Define build variables | -| cache | optional | Define list of files that should be cached between subsequent runs | +| image | no | Use docker image, covered in [Use Docker](../docker/README.md) | +| services | no | Use docker services, covered in [Use Docker](../docker/README.md) | +| stages | no | Define build stages | +| types | no | Alias for `stages` | +| before_script | no | Define commands that run before each job's script | +| variables | no | Define build variables | +| cache | no | Define list of files that should be cached between subsequent runs | ### image and services -This allows to specify a custom Docker image and a list of services that can be used for time of the build. -The configuration of this feature is covered in separate document: [Use Docker](../docker/README.md). + +This allows to specify a custom Docker image and a list of services that can be +used for time of the build. The configuration of this feature is covered in +separate document: [Use Docker](../docker/README.md). ### before_script -`before_script` is used to define the command that should be run before all builds, including deploy builds. This can be an array or a multiline string. + +`before_script` is used to define the command that should be run before all +builds, including deploy builds. This can be an array or a multi-line string. ### stages + `stages` is used to define build stages that can be used by jobs. The specification of `stages` allows for having flexible multi stage pipelines. @@ -75,7 +89,8 @@ The ordering of elements in `stages` defines the ordering of builds' execution: 1. Builds of next stage are run after success. Let's consider the following example, which defines 3 stages: -``` + +```yaml stages: - build - test @@ -86,21 +101,26 @@ stages: 1. If all jobs of `build` succeeds, the `test` jobs are executed in parallel. 1. If all jobs of `test` succeeds, the `deploy` jobs are executed in parallel. 1. If all jobs of `deploy` succeeds, the commit is marked as `success`. -1. If any of the previous jobs fails, the commit is marked as `failed` and no jobs of further stage are executed. +1. If any of the previous jobs fails, the commit is marked as `failed` and no + jobs of further stage are executed. There are also two edge cases worth mentioning: -1. If no `stages` is defined in `.gitlab-ci.yml`, then by default the `build`, `test` and `deploy` are allowed to be used as job's stage by default. +1. If no `stages` is defined in `.gitlab-ci.yml`, then by default the `build`, + `test` and `deploy` are allowed to be used as job's stage by default. 2. If a job doesn't specify `stage`, the job is assigned the `test` stage. ### types + Alias for [stages](#stages). ### variables -**This feature requires `gitlab-runner` with version equal or greater than 0.5.0.** -GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build environment. -The variables are stored in repository and are meant to store non-sensitive project configuration, ie. RAILS_ENV or DATABASE_URL. +_**Note:** Introduced in GitLab Runner v0.5.0._ + +GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build +environment. The variables are stored in the git repository and are meant to +store non-sensitive project configuration, for example: ```yaml variables: @@ -109,18 +129,23 @@ variables: These variables can be later used in all executed commands and scripts. -The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them. +The YAML-defined variables are also set to all created service containers, +thus allowing to fine tune them. ### cache -`cache` is used to specify list of files and directories which should be cached between builds. -Caches are stored according to the branch/ref and the job name. Caches are not -currently shared between different job names or between branches/refs. This means -caching will benefit you if you push subsequent commits to an existing feature branch. -**The global setting allows to specify default cached files for all jobs.** +`cache` is used to specify a list of files and directories which should be +cached between builds. Caches are stored according to the branch/ref and the +job name. They are not currently shared between different job names or between +branches/refs, which means that caching will benefit you if you push subsequent +commits to an existing feature branch. + +If `cache` is defined outside the scope of the jobs, it means it is set +globally and all jobs will use its definition. To cache all git untracked files and files in `binaries`: -``` + +```yaml cache: untracked: true paths: @@ -128,9 +153,10 @@ cache: ``` ## Jobs -`.gitlab-ci.yml` allows you to specify an unlimited number of jobs. -Each job has to have a unique `job_name`, which is not one of the keywords mentioned above. -A job is defined by a list of parameters that define the build behaviour. + +`.gitlab-ci.yml` allows you to specify an unlimited number of jobs. Each job +must have a unique name, which is not one of the Keywords mentioned above. +A job is defined by a list of parameters that define the build behavior. ```yaml job_name: @@ -148,21 +174,22 @@ job_name: allow_failure: true ``` -| keyword | required | description | +| Keyword | Required | Description | |---------------|----------|-------------| -| script | required | Defines a shell script which is executed by runner | -| stage | optional (default: test) | Defines a build stage | -| type | optional | Alias for `stage` | -| only | optional | Defines a list of git refs for which build is created | -| except | optional | Defines a list of git refs for which build is not created | -| tags | optional | Defines a list of tags which are used to select runner | -| allow_failure | optional | Allow build to fail. Failed build doesn't contribute to commit status | -| when | optional | Define when to run build. Can be `on_success`, `on_failure` or `always` | -| artifacts | optional | Define list build artifacts | -| cache | optional | Define list of files that should be cached between subsequent runs | +| script | yes | Defines a shell script which is executed by runner | +| stage | no (default: `test`) | Defines a build stage | +| type | no | Alias for `stage` | +| only | no | Defines a list of git refs for which build is created | +| except | no | Defines a list of git refs for which build is not created | +| tags | no | Defines a list of tags which are used to select runner | +| allow_failure | no | Allow build to fail. Failed build doesn't contribute to commit status | +| when | no | Define when to run build. Can be `on_success`, `on_failure` or `always` | +| artifacts | no | Define list build artifacts | +| cache | no | Define list of files that should be cached between subsequent runs | ### script -`script` is a shell script which is executed by runner. The shell script is prepended with `before_script`. + +`script` is a shell script which is executed by the runner. For example: ```yaml job: @@ -170,6 +197,7 @@ job: ``` This parameter can also contain several commands using an array: + ```yaml job: script: @@ -178,31 +206,45 @@ job: ``` ### stage -`stage` allows to group build into different stages. Builds of the same `stage` are executed in `parallel`. -For more info about the use of `stage` please check the [stages](#stages). + +`stage` allows to group build into different stages. Builds of the same `stage` +are executed in `parallel`. For more info about the use of `stage` please check +[stages](#stages). ### only and except -This are two parameters that allow for setting a refs policy to limit when jobs are built: -1. `only` defines the names of branches and tags for which job will be built. -2. `except` defines the names of branches and tags for which the job wil **not** be built. -There are a few rules that apply to usage of refs policy: +`only` and `except` are two parameters that set a refs policy to limit when +jobs are built: -1. `only` and `except` are inclusive. If both `only` and `except` are defined in job specification the ref is filtered by `only` and `except`. -1. `only` and `except` allow for using the regexp expressions. -1. `only` and `except` allow for using special keywords: `branches` and `tags`. -These names can be used for example to exclude all tags and all branches. +1. `only` defines the names of branches and tags for which the job will be + built. +2. `except` defines the names of branches and tags for which the job will + **not** be built. + +There are a few rules that apply to the usage of refs policy: + +* `only` and `except` are inclusive. If both `only` and `except` are defined + in a job specification, the ref is filtered by `only` and `except`. +* `only` and `except` allow the use of regular expressions. +* `only` and `except` allow the use of special keywords: `branches` and `tags`. +* `only` and `except` allow to specify a repository path to filter jobs for + forks. + +In the example below, `job` will run only for refs that start with `issue-`, +whereas all branches will be skipped. ```yaml job: + # use regexp only: - - /^issue-.*$/ # use regexp + - /^issue-.*$/ + # use special keyword except: - - branches # use special keyword + - branches ``` -1. `only` and `except` allow for specify repository path to filter jobs for forks. -The repository path can be used to have jobs executed only for parent repository. +The repository path can be used to have jobs executed only for the parent +repository and not forks: ```yaml job: @@ -211,33 +253,47 @@ job: except: - master@gitlab-org/gitlab-ce ``` -The above will run `job` for all branches on `gitlab-org/gitlab-ce`, except master . + +The above example will run `job` for all branches on `gitlab-org/gitlab-ce`, +except master. ### tags -`tags` is used to select specific runners from the list of all runners that are allowed to run this project. -During registration of a runner, you can specify the runner's tags, ie.: `ruby`, `postgres`, `development`. -`tags` allow you to run builds with runners that have the specified tags assigned: +`tags` is used to select specific runners from the list of all runners that are +allowed to run this project. -``` +During the registration of a runner, you can specify the runner's tags, for +example `ruby`, `postgres`, `development`. + +`tags` allow you to run builds with runners that have the specified tags +assigned to them: + +```yaml job: tags: - ruby - postgres ``` -The above specification will make sure that `job` is built by a runner that have `ruby` AND `postgres` tags defined. +The specification above, will make sure that `job` is built by a runner that +has both `ruby` AND `postgres` tags defined. ### when -`when` is used to implement jobs that are run in case of failure or despite the failure. + +`when` is used to implement jobs that are run in case of failure or despite the +failure. `when` can be set to one of the following values: -1. `on_success` - execute build only when all builds from prior stages succeeded. This is the default. -1. `on_failure` - execute build only when at least one build from prior stages failed. +1. `on_success` - execute build only when all builds from prior stages + succeeded. This is the default. +1. `on_failure` - execute build only when at least one build from prior stages + failed. 1. `always` - execute build despite the status of builds from prior stages. -``` +For example: + +```yaml stages: - build - cleanup_build @@ -245,28 +301,28 @@ stages: - deploy - cleanup -build: +build_job: stage: build script: - make build -cleanup_build: +cleanup_build_job: stage: cleanup_build script: - cleanup build when failed when: on_failure -test: +test_job: stage: test script: - make test -deploy: +deploy_job: stage: deploy script: - make deploy -cleanup: +cleanup_job: stage: cleanup script: - cleanup after builds @@ -274,84 +330,107 @@ cleanup: ``` The above script will: -1. Execute `cleanup_build` only when the `build` failed, -2. Always execute `cleanup` as the last step in pipeline. + +1. Execute `cleanup_build_job` only when `build_job` fails +2. Always execute `cleanup_job` as the last step in pipeline. ### artifacts -`artifacts` is used to specify list of files and directories which should be attached to build after success. -1. Send all files in `binaries` and `.config`: +_**Note:** Introduced in GitLab Runner v0.7.0._ - artifacts: - paths: - - binaries/ - - .config +`artifacts` is used to specify list of files and directories which should be +attached to build after success. Below are some examples. -2. Send all git untracked files: +Send all files in `binaries` and `.config`: - artifacts: - untracked: true +```yaml +artifacts: + paths: + - binaries/ + - .config +``` -3. Send all git untracked files and files in `binaries`: +Send all git untracked files: - artifacts: - untracked: true - paths: - - binaries/ +```yaml +artifacts: + untracked: true +``` + +Send all git untracked files and files in `binaries`: -The artifacts will be send after the build success to GitLab and will be accessible in GitLab interface to download. +```yaml +artifacts: + untracked: true + paths: + - binaries/ +``` -This feature requires GitLab Runner v0.7.0 or higher. +The artifacts will be send after a successful build success to GitLab, and will +be accessible in the GitLab UI to download. ### cache -`cache` is used to specify list of files and directories which should be cached between builds. -1. Cache all files in `binaries` and `.config`: +_**Note:** Introduced in GitLab Runner v0.7.0._ - rspec: - script: test - cache: - paths: - - binaries/ - - .config +`cache` is used to specify list of files and directories which should be cached +between builds. Below are some examples: -2. Cache all git untracked files: +Cache all files in `binaries` and `.config`: - rspec: - script: test - cache: - untracked: true - -3. Cache all git untracked files and files in `binaries`: +```yaml +rspec: + script: test + cache: + paths: + - binaries/ + - .config +``` - rspec: - script: test - cache: - untracked: true - paths: - - binaries/ +Cache all git untracked files: -4. Locally defined cache overwrites globally defined options. This will cache only `binaries/`: +```yaml +rspec: + script: test + cache: + untracked: true +``` + +Cache all git untracked files and files in `binaries`: + +```yaml +rspec: + script: test + cache: + untracked: true + paths: + - binaries/ +``` - cache: - paths: - - my/files - - rspec: - script: test - cache: - paths: - - binaries/ +Locally defined cache overwrites globally defined options. This will cache only +`binaries/`: -The cache is provided on best effort basis, so don't expect that cache will be present. -For implementation details please check GitLab Runner. +```yaml +cache: + paths: + - my/files -This feature requires GitLab Runner v0.7.0 or higher. +rspec: + script: test + cache: + paths: + - binaries/ +``` +The cache is provided on best effort basis, so don't expect that cache will be +always present. For implementation details please check GitLab Runner. ## Validate the .gitlab-ci.yml + Each instance of GitLab CI has an embedded debug tool called Lint. -You can find the link to the Lint in the project's settings page or use short url `/lint`. +You can find the link under `/ci/lint` of your gitlab instance. ## Skipping builds -There is one more way to skip all builds, if your commit message contains tag [ci skip]. In this case, commit will be created but builds will be skipped + +If your commit message contains `[ci skip]`, the commit will be created but the +builds will be skipped. diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index 0d340d97ff9..be993d11093 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -273,7 +273,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I should see merged request' do - page.within '.issue-box' do + page.within '.status-box' do expect(page).to have_content "Merged" end end @@ -283,7 +283,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I should see reopened merge request "Bug NS-04"' do - page.within '.issue-box' do + page.within '.status-box' do expect(page).to have_content "Open" end end diff --git a/features/steps/project/snippets.rb b/features/steps/project/snippets.rb index a3aef9bf8c3..504654f90dd 100644 --- a/features/steps/project/snippets.rb +++ b/features/steps/project/snippets.rb @@ -42,7 +42,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps end step 'I click link "Edit"' do - page.within ".page-title" do + page.within ".detail-page-header" do click_link "Edit" end end diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb index 80d1ddeef05..023032e679f 100644 --- a/features/steps/snippets/snippets.rb +++ b/features/steps/snippets/snippets.rb @@ -13,7 +13,7 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps end step 'I click link "Edit"' do - page.within ".page-title" do + page.within ".detail-page-header" do click_link "Edit" end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index a5daa45faf0..f8511ac5f5c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -70,6 +70,7 @@ module API expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ |project, options| project.forked? } expose :avatar_url expose :star_count, :forks_count + expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? } end class ProjectMember < UserBasic diff --git a/lib/api/projects.rb b/lib/api/projects.rb index bdf4b77596e..5e75cd35c56 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -39,6 +39,17 @@ module API present @projects, with: Entities::Project end + # Gets starred project for the authenticated user + # + # Example Request: + # GET /projects/starred + get '/starred' do + @projects = current_user.starred_projects + @projects = filter_projects(@projects) + @projects = paginate @projects + present @projects, with: Entities::Project + end + # Get all projects for admin user # # Example Request: diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index 891c0fd7749..115ae914524 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -1,5 +1,7 @@ module Banzai module Renderer + CACHE_ENABLED = false + # Convert a Markdown String into an HTML-safe String of HTML # # Note that while the returned HTML will have been sanitized of dangerous @@ -18,7 +20,7 @@ module Banzai cache_key = context.delete(:cache_key) cache_key = full_cache_key(cache_key, context[:pipeline]) - if cache_key + if cache_key && CACHE_ENABLED Rails.cache.fetch(cache_key) do cacheless_render(text, context) end diff --git a/spec/features/issues/filter_by_milestone_spec.rb b/spec/features/issues/filter_by_milestone_spec.rb index f600f8684ac..38c8d343ce3 100644 --- a/spec/features/issues/filter_by_milestone_spec.rb +++ b/spec/features/issues/filter_by_milestone_spec.rb @@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::None.title) - expect(page).to have_css('.issue-title', count: 1) + expect(page).to have_css('.title', count: 1) end scenario 'filters by a specific Milestone', js: true do @@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(milestone.title) - expect(page).to have_css('.issue-title', count: 1) + expect(page).to have_css('.title', count: 1) end def visit_issues(project) diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb index 28a46a0725d..7aa7eb965e9 100644 --- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -21,12 +21,12 @@ feature 'Merge When Build Succeeds', feature: true, js: true do end it 'displays the Merge When Build Succeeds button' do - expect(page).to have_link "Merge When Build Succeeds" + expect(page).to have_button "Merge When Build Succeeds" end context "Merge When Build succeeds enabled" do before do - click_link "Merge When Build Succeeds" + click_button "Merge When Build Succeeds" end it 'activates Merge When Build Succeeds feature' do @@ -58,7 +58,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do it 'cancels the automatic merge' do click_link "Cancel Automatic Merge" - expect(page).to have_link "Merge When Build Succeeds" + expect(page).to have_button "Merge When Build Succeeds" visit_merge_request(merge_request) # Needed to refresh the page expect(page).to have_content "Canceled the automatic merge" diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index fca3c77fc64..b7368cca29d 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -47,7 +47,7 @@ feature 'Task Lists', feature: true do it 'contains the required selectors' do visit_issue(project, issue) - container = '.issue-details .description.js-task-list-container' + container = '.detail-page-description .description.js-task-list-container' expect(page).to have_selector(container) expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox") @@ -123,7 +123,7 @@ feature 'Task Lists', feature: true do it 'contains the required selectors' do visit_merge_request(project, merge) - container = '.merge-request-details .description.js-task-list-container' + container = '.detail-page-description .description.js-task-list-container' expect(page).to have_selector(container) expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox") diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb index 7fc53eb1472..4f8d9c67262 100644 --- a/spec/helpers/ci_status_helper_spec.rb +++ b/spec/helpers/ci_status_helper_spec.rb @@ -6,13 +6,8 @@ describe CiStatusHelper do let(:success_commit) { double("Ci::Commit", status: 'success') } let(:failed_commit) { double("Ci::Commit", status: 'failed') } - describe 'ci_status_color' do - it { expect(ci_status_icon(success_commit)).to include('fa-check') } - it { expect(ci_status_icon(failed_commit)).to include('fa-close') } - end - - describe 'ci_status_color' do - it { expect(ci_status_color(success_commit)).to eq('green') } - it { expect(ci_status_color(failed_commit)).to eq('red') } + describe 'ci_status_icon' do + it { expect(helper.ci_status_icon(success_commit)).to include('fa-check') } + it { expect(helper.ci_status_icon(failed_commit)).to include('fa-close') } end end diff --git a/spec/javascripts/fixtures/issues_show.html.haml b/spec/javascripts/fixtures/issues_show.html.haml index 7e8b2a64351..8447dfdda32 100644 --- a/spec/javascripts/fixtures/issues_show.html.haml +++ b/spec/javascripts/fixtures/issues_show.html.haml @@ -1,6 +1,6 @@ %a.btn-close -.issue-details +.detail-page-description .description.js-task-list-container .wiki %ul.task-list diff --git a/spec/javascripts/fixtures/merge_requests_show.html.haml b/spec/javascripts/fixtures/merge_requests_show.html.haml index f0c622935f8..8447dfdda32 100644 --- a/spec/javascripts/fixtures/merge_requests_show.html.haml +++ b/spec/javascripts/fixtures/merge_requests_show.html.haml @@ -1,6 +1,6 @@ %a.btn-close -.merge-request-details +.detail-page-description .description.js-task-list-container .wiki %ul.task-list diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 87582e07494..c4d3813e9c9 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -172,13 +172,17 @@ describe Project, models: true do describe '#get_issue' do let(:project) { create(:empty_project) } - let(:issue) { create(:issue, project: project) } + let!(:issue) { create(:issue, project: project) } context 'with default issues tracker' do it 'returns an issue' do expect(project.get_issue(issue.iid)).to eq issue end + it 'returns count of open issues' do + expect(project.open_issues_count).to eq(1) + end + it 'returns nil when no issue found' do expect(project.get_issue(999)).to be_nil end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index e784b7d1f2d..01d2ec79482 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -65,6 +65,22 @@ describe API::API, api: true do expect(json_response.first.keys).to include('tag_list') end + it 'should include open_issues_count' do + get api('/projects', user) + expect(response.status).to eq 200 + expect(json_response).to be_an Array + expect(json_response.first.keys).to include('open_issues_count') + end + + it 'should not include open_issues_count' do + project.update_attributes( { issues_enabled: false } ) + + get api('/projects', user) + expect(response.status).to eq 200 + expect(json_response).to be_an Array + expect(json_response.first.keys).not_to include('open_issues_count') + end + context 'and using search' do it 'should return searched project' do get api('/projects', user), { search: project.name } @@ -123,6 +139,25 @@ describe API::API, api: true do end end + describe 'GET /projects/starred' do + before do + admin.starred_projects << project + admin.save! + end + + it 'should return the starred projects' do + get api('/projects/all', admin) + expect(response.status).to eq(200) + expect(json_response).to be_an Array + + expect(json_response).to satisfy do |response| + response.one? do |entry| + entry['name'] == project.name + end + end + end + end + describe 'POST /projects' do context 'maximum number of projects reached' do it 'should not create new project and respond with 403' do @@ -455,7 +490,7 @@ describe API::API, api: true do end end - describe 'PUT /projects/:id/snippets/:shippet_id' do + describe 'PUT /projects/:id/snippets/:snippet_id' do it 'should update an existing project snippet' do put api("/projects/#{project.id}/snippets/#{snippet.id}", user), code: 'updated code' |