diff options
69 files changed, 738 insertions, 597 deletions
diff --git a/CHANGELOG b/CHANGELOG index 6ae1f8cbcde..422c6f07b15 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,11 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.3.0 (unreleased) + - Bump rack-attack to 4.3.1 for security fix (Stan Hu) + - 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) - Provide better diagnostic message upon project creation errors (Stan Hu) - Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu) - Bump gollum-lib to 4.1.0 (Stan Hu) @@ -24,6 +26,7 @@ v 8.3.0 (unreleased) - Migrate all CI::Services and CI::WebHooks to Services and WebHooks - Don't show project fork event as "imported" - Add API endpoint to fetch merge request commits list + - Don't create CI status for refs that doesn't have .gitlab-ci.yml, even if the builds are enabled - Expose events API with comment information and author info - Fix: Ensure "Remove Source Branch" button is not shown when branch is being deleted. #3583 - Run custom Git hooks when branch is created or deleted. diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 743af5e1251..d48d3702aed 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.6.8 +2.6.9 diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 8f0916f768f..4b9fcbec101 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.5.0 +0.5.1 @@ -175,7 +175,7 @@ gem "sanitize", '~> 2.0' gem 'babosa', '~> 1.0.2' # Protect against bruteforcing -gem "rack-attack", '~> 4.3.0' +gem "rack-attack", '~> 4.3.1' # Ace editor gem 'ace-rails-ap', '~> 2.0.1' @@ -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' @@ -251,7 +251,7 @@ group :development, :test do gem 'capybara', '~> 2.4.0' gem 'capybara-screenshot', '~> 1.0.0' - gem 'poltergeist', '~> 1.6.0' + gem 'poltergeist', '~> 1.8.1' gem 'teaspoon', '~> 1.0.0' gem 'teaspoon-jasmine', '~> 2.2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 796c90573cc..88c7a6e3424 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) @@ -424,7 +405,7 @@ GEM method_source (0.8.2) mime-types (1.25.1) mimemagic (0.3.0) - mini_portile (0.6.2) + mini_portile2 (2.0.0) minitest (5.7.0) mousetrap-rails (1.4.6) multi_json (1.11.2) @@ -439,8 +420,8 @@ GEM grape newrelic_rpm newrelic_rpm (3.9.4.245) - nokogiri (1.6.6.4) - mini_portile (~> 0.6.0) + nokogiri (1.6.7) + mini_portile2 (~> 2.0.0.rc2) nprogress-rails (0.1.6.7) oauth (0.4.7) oauth2 (1.0.0) @@ -507,7 +488,7 @@ GEM parser (2.2.3.0) ast (>= 1.1, < 3.0) pg (0.18.4) - poltergeist (1.6.0) + poltergeist (1.8.1) capybara (~> 2.1) cliver (~> 0.3.1) multi_json (~> 1.0) @@ -526,7 +507,7 @@ GEM rack (1.6.4) rack-accept (0.4.5) rack (>= 0.4) - rack-attack (4.3.0) + rack-attack (4.3.1) rack rack-cors (0.4.0) rack-mount (0.8.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) @@ -926,10 +905,10 @@ DEPENDENCIES org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) - poltergeist (~> 1.6.0) + poltergeist (~> 1.8.1) pry-rails quiet_assets (~> 1.0.2) - rack-attack (~> 4.3.0) + rack-attack (~> 4.3.1) rack-cors (~> 0.4.0) rack-oauth2 (~> 1.2.1) rails (= 4.2.4) @@ -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/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss index f12d68b5a1f..fba67ba0b64 100644 --- a/app/assets/stylesheets/framework/issue_box.scss +++ b/app/assets/stylesheets/framework/issue_box.scss @@ -4,7 +4,7 @@ * */ -.issue-box { +.status-box { @include border-radius(2px); display: block; @@ -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 { + &.status-box-open { background-color: #019875; 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/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/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 797a0af3720..9da273a0b6b 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; - } } } @@ -136,21 +115,3 @@ margin-right: 2px; } } - -.issuable-title { - 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; - } - - .issuable-id { - color: #5c5d5e; - } -} 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 e1a72af0013..4cf1a28c459 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/ci/commit.rb b/app/models/ci/commit.rb index 6bf596e5d3e..d2a29236942 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -218,16 +218,6 @@ module Ci update!(committed_at: DateTime.now) end - ## - # This method checks if build status should be displayed. - # - # Build status should be available only if builds are enabled - # on project level and `.gitlab-ci.yml` file is present. - # - def show_build_status? - project.builds_enabled? && ci_yaml_file - end - private def save_yaml_error(error) 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/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb index 759c334ebe9..31b407efeb1 100644 --- a/app/services/create_commit_builds_service.rb +++ b/app/services/create_commit_builds_service.rb @@ -16,9 +16,23 @@ class CreateCommitBuildsService return false end - tag = Gitlab::Git.tag_ref?(origin_ref) - commit = project.ensure_ci_commit(sha) + commit = project.ci_commit(sha) + unless commit + commit = project.ci_commits.new(sha: sha) + + # Skip creating ci_commit when no gitlab-ci.yml is found + unless commit.ci_yaml_file + return false + end + + # Create a new ci_commit + commit.save! + end + + # Skip creating builds for commits that have [ci skip] unless commit.skip_ci? + # Create builds for commit + tag = Gitlab::Git.tag_ref?(origin_ref) commit.update_committed! commit.create_builds(ref, tag, user) 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/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index cd40bfafcc2..ddb77fd796b 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -40,7 +40,7 @@ - @commit.parents.each do |parent| = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace" -- if @ci_commit && @ci_commit.show_build_status? +- if @ci_commit .pull-right = link_to ci_status_path(@ci_commit), class: "ci-status ci-#{@ci_commit.status}" do = ci_status_icon(@ci_commit) 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/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 1303b27c4f3..28b82dd31f3 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -17,7 +17,7 @@ %a.text-expander.js-toggle-button ... .pull-right - - if ci_commit && ci_commit.show_build_status? + - if ci_commit = render_ci_status(ci_commit) = clipboard_button(clipboard_text: commit.id) 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 405bae1bbb9..86d3dc546ba 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-grouped btn-close 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/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml index fe856ac991e..254968e4f67 100644 --- a/app/views/projects/issues/_merge_requests.html.haml +++ b/app/views/projects/issues/_merge_requests.html.haml @@ -15,9 +15,10 @@ %span.merge-request-info %strong = link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title" - in - - project = merge_request.target_project - = link_to project.name_with_namespace, namespace_project_path(project.namespace, project) + - unless @issue.project.id == merge_request.target_project.id + in + - project = merge_request.target_project + = link_to project.name_with_namespace, namespace_project_path(project.namespace, project) %span.merge-request-status.prepend-left-10 - if merge_request.merged? MERGED diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index cc2cf8c8716..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 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? - = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen' - - else - = link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-close', 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 issuable-edit' 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..473124480ac 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)} @@ -16,9 +17,9 @@ .issue-btn-group.pull-right - if can?(current_user, :update_merge_request, @merge_request) - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request" - = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "btn btn-grouped issuable-edit", id: "edit_merge_request" do + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-grouped btn-close', title: 'Close merge request' + = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-grouped issuable-edit', id: 'edit_merge_request' do %i.fa.fa-pencil-square-o Edit - 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", title: "Close merge request" + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request' diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index 6f52c963a53..d1d602eecdc 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -8,19 +8,15 @@ #{time_ago_with_tooltip(@merge_request.merge_event.created_at)} %div - if !@merge_request.source_branch_exists? || (params[:delete_source] == 'true') - = succeed '.' do - The changes were merged into - = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do - = @merge_request.target_branch + The changes were merged into + #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. The source branch has been removed. - elsif @merge_request.can_remove_source_branch?(current_user) .remove_source_branch_widget %p - = succeed '.' do - The changes were merged into - = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do - = @merge_request.target_branch + The changes were merged into + #{link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch"}. You can remove the source branch now. = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request.source_branch), remote: true, method: :delete, class: "btn btn-primary btn-sm remove_source_branch" do %i.fa.fa-times 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/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index cefe33e581f..89b072cea92 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -20,16 +20,24 @@ %li = link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'Create file', id: 'new-file-link' do = icon('pencil fw') - Create file + New file %li = link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'} do = icon('file fw') Upload file - %li.divider %li = link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal'} do = icon('folder fw') New directory + %li.divider + %li + = link_to new_namespace_project_branch_path(@project.namespace, @project) do + = icon('code-fork fw') + New branch + %li + = link_to new_namespace_project_tag_path(@project.namespace, @project) do + = icon('tags fw') + New tag - elsif !on_top_of_branch? %li %span.btn.btn-sm.add-to-tree.disabled.has_tooltip{title: "You can only add files when you are on a branch.", data: {container: 'body'}} 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..fd0d49de4e4 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,108 @@ 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. Also, the Windows shell executor + does not currently support artifact uploads._ - 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/doc/install/installation.md b/doc/install/installation.md index d4b5c01f72d..81edd8da2b8 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci cd /home/git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git cd gitlab-workhorse - sudo -u git -H git checkout 0.5.0 + sudo -u git -H git checkout 0.5.1 sudo -u git -H make ### Initialize Database and Activate Advanced Features diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md index 8ea2b674a1c..c4661dc16af 100644 --- a/doc/update/8.2-to-8.3.md +++ b/doc/update/8.2-to-8.3.md @@ -67,7 +67,7 @@ sudo -u git -H git checkout 8-3-stable-ee ```bash cd /home/git/gitlab-shell sudo -u git -H git fetch --all -sudo -u git -H git checkout v2.6.8 +sudo -u git -H git checkout v2.6.9 ``` ### 5. Update gitlab-workhorse @@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1. ```bash cd /home/git/gitlab-workhorse sudo -u git -H git fetch --all -sudo -u git -H git checkout 0.5.0 +sudo -u git -H git checkout 0.5.1 sudo -u git -H make ``` diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index d3675060994..cbdce78dc0c 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -41,7 +41,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps click_button "Compare branches and continue" - expect(page).to have_content "New Merge Request" + expect(page).to have_css("h3.page-title", text: "New Merge Request") + fill_in "merge_request_title", with: "Merge Request On Forked Project" end 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/shared/diff_note.rb b/features/steps/shared/diff_note.rb index dd466cde28d..c6a0ae2ba38 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -166,7 +166,7 @@ module SharedDiffNote end step 'I should see add a diff comment button' do - expect(page).to have_css('.js-add-diff-note-button', visible: true) + expect(page).to have_css('.js-add-diff-note-button') end step 'I should see an empty diff comment form' do 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/commits_spec.rb b/spec/features/commits_spec.rb index ecc85376ffc..fe7f07f5b75 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -19,30 +19,13 @@ describe 'Commits' do let!(:build) { FactoryGirl.create :ci_build, commit: commit } describe 'Project commits' do - context 'builds enabled' do - context '.gitlab-ci.yml found' do - before do - visit namespace_project_commits_path(project.namespace, project, :master) - end - - it 'should show build status' do - page.within("//li[@id='commit-#{commit.short_sha}']") do - expect(page).to have_css(".ci-status-link") - end - end - end + before do + visit namespace_project_commits_path(project.namespace, project, :master) + end - context 'no .gitlab-ci.yml found' do - before do - stub_ci_commit_yaml_file(nil) - visit namespace_project_commits_path(project.namespace, project, :master) - end - - it 'should not show build status' do - page.within("//li[@id='commit-#{commit.short_sha}']") do - expect(page).to have_no_css(".ci-status-link") - end - end + it 'should show build status' do + page.within("//li[@id='commit-#{commit.short_sha}']") do + expect(page).to have_css(".ci-status-link") end end 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' diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb index 40ba6549e1f..ea5dcfa068a 100644 --- a/spec/services/create_commit_builds_service_spec.rb +++ b/spec/services/create_commit_builds_service_spec.rb @@ -52,7 +52,7 @@ describe CreateCommitBuildsService, services: true do end end - it 'skips commits without .gitlab-ci.yml' do + it 'skips creating ci_commit for refs without .gitlab-ci.yml' do stub_ci_commit_yaml_file(nil) result = service.execute(project, user, ref: 'refs/heads/0_1', @@ -60,13 +60,11 @@ describe CreateCommitBuildsService, services: true do after: '31das312', commits: [{ message: 'Message' }] ) - expect(result).to be_persisted - expect(result.builds.any?).to be_falsey - expect(result.status).to eq('skipped') - expect(result.yaml_errors).to be_nil + expect(result).to be_falsey + expect(Ci::Commit.count).to eq(0) end - it 'skips commits if yaml is invalid' do + it 'fails commits if yaml is invalid' do message = 'message' allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message } stub_ci_commit_yaml_file('invalid: file: file') @@ -77,6 +75,7 @@ describe CreateCommitBuildsService, services: true do after: '31das312', commits: commits ) + expect(commit).to be_persisted expect(commit.builds.any?).to be false expect(commit.status).to eq('failed') expect(commit.yaml_errors).to_not be_nil @@ -97,6 +96,7 @@ describe CreateCommitBuildsService, services: true do after: '31das312', commits: commits ) + expect(commit).to be_persisted expect(commit.builds.any?).to be false expect(commit.status).to eq("skipped") end @@ -112,6 +112,7 @@ describe CreateCommitBuildsService, services: true do commits: commits ) + expect(commit).to be_persisted expect(commit.builds.first.name).to eq("staging") end @@ -124,6 +125,7 @@ describe CreateCommitBuildsService, services: true do after: '31das312', commits: commits ) + expect(commit).to be_persisted expect(commit.builds.any?).to be false expect(commit.status).to eq("skipped") expect(commit.yaml_errors).to be_nil @@ -140,6 +142,7 @@ describe CreateCommitBuildsService, services: true do after: '31das312', commits: commits ) + expect(commit).to be_persisted expect(commit.builds.count(:all)).to eq(2) commit = service.execute(project, user, @@ -148,6 +151,7 @@ describe CreateCommitBuildsService, services: true do after: '31das312', commits: commits ) + expect(commit).to be_persisted expect(commit.builds.count(:all)).to eq(2) end @@ -163,6 +167,7 @@ describe CreateCommitBuildsService, services: true do commits: commits ) + expect(commit).to be_persisted expect(commit.status).to eq("failed") expect(commit.builds.any?).to be false end |