From 52c8651a6caf5236ff173555164b676958540b9e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 8 May 2017 12:00:30 +1000 Subject: Fix notify_only_default_branch check for Slack service The notify_only_default_branch property is using boolean_accessor this means we need to check it using a question methods. Also add specs for disabling this option. --- app/models/project_services/chat_notification_service.rb | 2 +- changelogs/unreleased/mrchrisw-fix-slack-notify.yml | 4 ++++ .../slack_mattermost_notifications_shared_examples.rb | 14 +++++++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/mrchrisw-fix-slack-notify.yml diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb index fa782c6fbb7..6464bf3f4a4 100644 --- a/app/models/project_services/chat_notification_service.rb +++ b/app/models/project_services/chat_notification_service.rb @@ -150,7 +150,7 @@ class ChatNotificationService < Service def notify_for_ref?(data) return true if data[:object_attributes][:tag] - return true unless notify_only_default_branch + return true unless notify_only_default_branch? data[:object_attributes][:ref] == project.default_branch end diff --git a/changelogs/unreleased/mrchrisw-fix-slack-notify.yml b/changelogs/unreleased/mrchrisw-fix-slack-notify.yml new file mode 100644 index 00000000000..bb45a117be6 --- /dev/null +++ b/changelogs/unreleased/mrchrisw-fix-slack-notify.yml @@ -0,0 +1,4 @@ +--- +title: Fix notify_only_default_branch check for Slack service +merge_request: +author: diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb index b902fe90707..7e35ebb6c97 100644 --- a/spec/support/slack_mattermost_notifications_shared_examples.rb +++ b/spec/support/slack_mattermost_notifications_shared_examples.rb @@ -328,7 +328,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do context 'only notify for the default branch' do context 'when enabled' do let(:pipeline) do - create(:ci_pipeline, project: project, status: 'failed', ref: 'not-the-default-branch') + create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch') end before do @@ -342,6 +342,18 @@ RSpec.shared_examples 'slack or mattermost notifications' do expect(result).to be_falsy end end + + context 'when disabled' do + let(:pipeline) do + create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch') + end + + before do + chat_service.notify_only_default_branch = false + end + + it_behaves_like 'call Slack/Mattermost API' + end end end end -- cgit v1.2.1 From 694f31dd40b7bfcdab57f40802df715961f1cbe6 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 8 May 2017 12:18:32 +0200 Subject: Fix skipped manual actions issue in pipeline processing --- app/services/ci/process_pipeline_service.rb | 2 +- .../fix-gb-fix-skipped-manual-actions.yml | 4 ++++ spec/services/ci/process_pipeline_service_spec.rb | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/fix-gb-fix-skipped-manual-actions.yml diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb index 33edcd60944..25ba54ffa0d 100644 --- a/app/services/ci/process_pipeline_service.rb +++ b/app/services/ci/process_pipeline_service.rb @@ -50,7 +50,7 @@ module Ci when 'always' %w[success failed skipped] when 'manual' - %w[success] + %w[success skipped] else [] end diff --git a/changelogs/unreleased/fix-gb-fix-skipped-manual-actions.yml b/changelogs/unreleased/fix-gb-fix-skipped-manual-actions.yml new file mode 100644 index 00000000000..d8d4c668a44 --- /dev/null +++ b/changelogs/unreleased/fix-gb-fix-skipped-manual-actions.yml @@ -0,0 +1,4 @@ +--- +title: Fix skipped manual actions problem when processing the pipeline +merge_request: 11164 +author: diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index cf773866a6f..1d0a28210fb 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -268,6 +268,24 @@ describe Ci::ProcessPipelineService, '#execute', :services do end end + context 'when there are only manual actions in stages' do + before do + create_build('image', stage_idx: 0, when: 'manual', allow_failure: true) + create_build('build', stage_idx: 1, when: 'manual', allow_failure: true) + create_build('deploy', stage_idx: 2, when: 'manual') + create_build('check', stage_idx: 3) + + process_pipeline + end + + it 'processes all jobs until blocking actions encountered' do + expect(all_builds_statuses).to eq(%w[manual manual manual created]) + expect(all_builds_names).to eq(%w[image build deploy check]) + + expect(pipeline.reload).to be_blocked + end + end + context 'when blocking manual actions are defined' do before do create_build('code:test', stage_idx: 0) @@ -441,6 +459,10 @@ describe Ci::ProcessPipelineService, '#execute', :services do builds.pluck(:name) end + def all_builds_names + all_builds.pluck(:name) + end + def builds_statuses builds.pluck(:status) end -- cgit v1.2.1 From ee01ebd9e4be07090cd5afb7ea69d4a301dbf642 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 8 May 2017 14:31:11 +0100 Subject: Fixed UP arrow key not editing last comment in discussion Closes #31348 --- app/assets/javascripts/notes.js | 2 +- .../up-arrow-focus-discussion-comment.yml | 4 ++ spec/javascripts/fixtures/merge_requests.rb | 16 ++++++ spec/javascripts/merge_request_notes_spec.js | 61 ++++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/up-arrow-focus-discussion-comment.yml create mode 100644 spec/javascripts/merge_request_notes_spec.js diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 55391ebc089..80adf8f0885 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -175,7 +175,7 @@ const normalizeNewlines = function(str) { if ($textarea.val() !== '') { return; } - myLastNote = $("li.note[data-author-id='" + gon.current_user_id + "'][data-editable]:last"); + myLastNote = $(`li.note[data-author-id='${gon.current_user_id}'][data-editable]:last`, $textarea.closest('.note, #notes')); if (myLastNote.length) { myLastNoteEditBtn = myLastNote.find('.js-note-edit'); return myLastNoteEditBtn.trigger('click', [true, myLastNote]); diff --git a/changelogs/unreleased/up-arrow-focus-discussion-comment.yml b/changelogs/unreleased/up-arrow-focus-discussion-comment.yml new file mode 100644 index 00000000000..5457dab6d3d --- /dev/null +++ b/changelogs/unreleased/up-arrow-focus-discussion-comment.yml @@ -0,0 +1,4 @@ +--- +title: Fix up arrow not editing last discussion comment +merge_request: +author: diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 47d904b865b..a746a776548 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -16,6 +16,16 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont sha: merge_request.diff_head_sha ) end + let(:path) { "files/ruby/popen.rb" } + let(:position) do + Gitlab::Diff::Position.new( + old_path: path, + new_path: path, + old_line: nil, + new_line: 14, + diff_refs: merge_request.diff_refs + ) + end render_views @@ -39,6 +49,12 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont render_merge_request(example.description, merged_merge_request) end + it 'merge_requests/diff_comment.html.raw' do |example| + create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) + create(:note_on_merge_request, author: admin, project: project, noteable: merge_request) + render_merge_request(example.description, merge_request) + end + private def render_merge_request(fixture_file_name, merge_request) diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js new file mode 100644 index 00000000000..86a4a70da42 --- /dev/null +++ b/spec/javascripts/merge_request_notes_spec.js @@ -0,0 +1,61 @@ +/* global Notes */ + +import 'vendor/autosize'; +import '~/gl_form'; +import '~/lib/utils/text_utility'; +import '~/render_gfm'; +import '~/render_math'; +import '~/notes'; + +fdescribe('Merge request notes', () => { + window.gon = window.gon || {}; + window.gl = window.gl || {}; + gl.utils = gl.utils || {}; + + const fixture = 'merge_requests/diff_comment.html.raw'; + preloadFixtures(fixture); + + beforeEach(() => { + loadFixtures(fixture); + gl.utils.disableButtonIfEmptyField = _.noop; + window.project_uploads_path = 'http://test.host/uploads'; + $('body').data('page', 'projects:merge_requests:show'); + window.gon.current_user_id = $('.note:last').data('author-id'); + + return new Notes('', []); + }); + + describe('up arrow', () => { + it('edits last comment when triggered in main form', () => { + const upArrowEvent = $.Event('keydown'); + upArrowEvent.which = 38; + + spyOnEvent('.note:last .js-note-edit', 'click'); + + $('.js-note-text').trigger(upArrowEvent); + + expect('click').toHaveBeenTriggeredOn('.note:last .js-note-edit'); + }); + + it('edits last comment in discussion when triggered in discussion form', (done) => { + const upArrowEvent = $.Event('keydown'); + upArrowEvent.which = 38; + + spyOnEvent('.note-discussion .js-note-edit', 'click'); + + $('.js-discussion-reply-button').click(); + + setTimeout(() => { + expect( + $('.note-discussion .js-note-text'), + ).toExist(); + + $('.note-discussion .js-note-text').trigger(upArrowEvent); + + expect('click').toHaveBeenTriggeredOn('.note-discussion .js-note-edit'); + + done(); + }); + }); + }); +}); -- cgit v1.2.1 From 81b1b7633bef1da1f2db04b2a9decdea0042d93a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 8 May 2017 14:59:18 +0100 Subject: Fixed focused test in notes spec --- spec/javascripts/merge_request_notes_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js index 86a4a70da42..e54acfa8e44 100644 --- a/spec/javascripts/merge_request_notes_spec.js +++ b/spec/javascripts/merge_request_notes_spec.js @@ -7,7 +7,7 @@ import '~/render_gfm'; import '~/render_math'; import '~/notes'; -fdescribe('Merge request notes', () => { +describe('Merge request notes', () => { window.gon = window.gon || {}; window.gl = window.gl || {}; gl.utils = gl.utils || {}; -- cgit v1.2.1 From 0151325dacebb99d54b6effb1d5842c0c712168c Mon Sep 17 00:00:00 2001 From: Fatih Acet Date: Tue, 9 May 2017 04:15:34 +0000 Subject: Merge request widget redesign --- .../diff_notes/components/resolve_btn.js | 1 + .../javascripts/diff_notes/services/resolve.js | 1 + app/assets/javascripts/dispatcher.js | 6 - app/assets/javascripts/lib/utils/simple_poll.js | 15 + app/assets/javascripts/main.js | 2 - app/assets/javascripts/merge_request.js | 15 + .../javascripts/merge_request_widget/ci_bundle.js | 53 --- app/assets/javascripts/merged_buttons.js | 47 --- app/assets/javascripts/notes.js | 12 +- .../javascripts/pipelines/components/stage.js | 104 ++++++ .../components/mr_widget_author.js | 23 ++ .../components/mr_widget_author_time.js | 27 ++ .../components/mr_widget_deployment.js | 118 +++++++ .../components/mr_widget_header.js | 98 ++++++ .../components/mr_widget_memory_usage.js | 109 ++++++ .../components/mr_widget_merge_help.js | 23 ++ .../components/mr_widget_pipeline.js | 76 ++++ .../components/mr_widget_related_links.js | 42 +++ .../components/states/mr_widget_archived.js | 16 + .../states/mr_widget_auto_merge_failed.js | 22 ++ .../components/states/mr_widget_checking.js | 19 + .../components/states/mr_widget_closed.js | 30 ++ .../components/states/mr_widget_conflicts.js | 39 +++ .../components/states/mr_widget_failed_to_merge.js | 76 ++++ .../components/states/mr_widget_locked.js | 24 ++ .../mr_widget_merge_when_pipeline_succeeds.js | 116 ++++++ .../components/states/mr_widget_merged.js | 130 +++++++ .../components/states/mr_widget_missing_branch.js | 34 ++ .../components/states/mr_widget_not_allowed.js | 17 + .../states/mr_widget_nothing_to_merge.js | 17 + .../states/mr_widget_pipeline_blocked.js | 16 + .../components/states/mr_widget_pipeline_failed.js | 16 + .../components/states/mr_widget_ready_to_merge.js | 309 ++++++++++++++++ .../states/mr_widget_squash_before_merge.js | 15 + .../states/mr_widget_unresolved_discussions.js | 27 ++ .../components/states/mr_widget_wip.js | 59 ++++ .../vue_merge_request_widget/dependencies.js | 42 +++ .../vue_merge_request_widget/event_hub.js | 3 + .../javascripts/vue_merge_request_widget/index.js | 12 + .../vue_merge_request_widget/mr_widget_options.js | 234 +++++++++++++ .../services/mr_widget_service.js | 57 +++ .../stores/get_state_key.js | 28 ++ .../stores/mr_widget_store.js | 134 +++++++ .../vue_merge_request_widget/stores/state_maps.js | 36 ++ .../vue_shared/components/memory_graph.js | 36 ++ .../vue_shared/components/pipeline_status_icon.js | 23 ++ .../javascripts/vue_shared/pipeline_svg_icons.js | 43 +++ app/assets/stylesheets/framework.scss | 1 + app/assets/stylesheets/framework/common.scss | 3 +- app/assets/stylesheets/framework/icons.scss | 3 +- app/assets/stylesheets/framework/memory_graph.scss | 16 + app/assets/stylesheets/framework/variables.scss | 1 + app/assets/stylesheets/pages/merge_requests.scss | 257 +++++++++++--- app/controllers/application_controller.rb | 5 +- app/controllers/projects/branches_controller.rb | 1 + app/controllers/projects/builds_controller.rb | 2 +- app/controllers/projects/commit_controller.rb | 2 +- app/controllers/projects/deployments_controller.rb | 14 + .../projects/environments_controller.rb | 18 +- .../projects/merge_requests_controller.rb | 167 ++++----- app/controllers/projects/pipelines_controller.rb | 6 +- app/helpers/issuables_helper.rb | 5 +- app/helpers/merge_requests_helper.rb | 54 --- app/models/deployment.rb | 15 + app/models/merge_request.rb | 4 +- app/models/project_services/monitoring_service.rb | 2 +- app/models/project_services/prometheus_service.rb | 25 +- app/presenters/merge_request_presenter.rb | 168 +++++++++ app/serializers/base_serializer.rb | 6 +- app/serializers/build_action_entity.rb | 2 +- app/serializers/build_entity.rb | 4 +- app/serializers/environment_entity.rb | 2 +- app/serializers/event_entity.rb | 4 + app/serializers/job_group_entity.rb | 2 +- app/serializers/merge_request_basic_entity.rb | 10 + app/serializers/merge_request_basic_serializer.rb | 3 + app/serializers/merge_request_entity.rb | 172 +++++++++ app/serializers/merge_request_serializer.rb | 8 +- app/serializers/pipeline_entity.rb | 8 +- app/serializers/pipeline_serializer.rb | 7 + app/serializers/stage_entity.rb | 2 +- app/views/layouts/nav/_project.html.haml | 2 +- app/views/projects/merge_requests/_show.html.haml | 45 +-- .../cancel_merge_when_pipeline_succeeds.js.haml | 2 - app/views/projects/merge_requests/merge.js.haml | 14 - .../merge_requests/widget/_closed.html.haml | 12 - .../widget/_commit_change_content.html.haml | 4 + .../merge_requests/widget/_heading.html.haml | 50 --- .../merge_requests/widget/_locked.html.haml | 9 - .../merge_requests/widget/_merged.html.haml | 52 --- .../merge_requests/widget/_merged_buttons.haml | 14 - .../projects/merge_requests/widget/_open.html.haml | 49 --- .../projects/merge_requests/widget/_show.html.haml | 40 --- .../merge_requests/widget/open/_accept.html.haml | 50 --- .../merge_requests/widget/open/_archived.html.haml | 4 - .../widget/open/_build_failed.html.haml | 6 - .../merge_requests/widget/open/_check.html.haml | 6 - .../widget/open/_conflicts.html.haml | 27 -- .../merge_requests/widget/open/_manual.html.haml | 4 - .../open/_merge_when_pipeline_succeeds.html.haml | 33 -- .../widget/open/_missing_branch.html.haml | 16 - .../widget/open/_not_allowed.html.haml | 6 - .../merge_requests/widget/open/_nothing.html.haml | 8 - .../merge_requests/widget/open/_reload.html.haml | 6 - .../widget/open/_sha_mismatch.html.haml | 6 - .../widget/open/_unresolved_discussions.html.haml | 10 - .../merge_requests/widget/open/_wip.html.haml | 11 - .../shared/issuable/form/_merge_params.html.haml | 9 - config/routes/project.rb | 9 +- config/webpack.config.js | 2 +- doc/user/project/integrations/prometheus.md | 9 + features/project/commits/revert.feature | 3 + features/project/merge_requests.feature | 7 + features/project/merge_requests/accept.feature | 3 +- features/steps/project/commits/revert.rb | 1 + features/steps/project/forked_merge_requests.rb | 3 + features/steps/project/merge_requests.rb | 25 +- .../steps/project/merge_requests/acceptance.rb | 18 +- features/steps/project/merge_requests/revert.rb | 4 +- features/steps/shared/paths.rb | 6 + features/support/env.rb | 2 +- lib/gitlab/prometheus.rb | 8 +- .../projects/branches_controller_spec.rb | 97 ++++- .../projects/deployments_controller_spec.rb | 55 ++- .../projects/environments_controller_spec.rb | 42 +++ .../projects/merge_requests_controller_spec.rb | 234 +++++-------- spec/features/boards/issue_ordering_spec.rb | 2 + ..._issue_for_discussions_in_merge_request_spec.rb | 8 +- spec/features/merge_requests/assign_issues_spec.rb | 2 +- ...f_mergeable_with_unresolved_discussions_spec.rb | 10 +- spec/features/merge_requests/cherry_pick_spec.rb | 2 +- spec/features/merge_requests/closes_issues_spec.rb | 15 +- .../merge_requests/created_from_fork_spec.rb | 2 +- .../merge_requests/deleted_source_branch_spec.rb | 4 +- spec/features/merge_requests/edit_mr_spec.rb | 12 - .../merge_commit_message_toggle_spec.rb | 19 +- .../merge_immediately_with_pipeline_spec.rb | 2 +- .../merge_when_pipeline_succeeds_spec.rb | 17 +- .../only_allow_merge_if_build_succeeds_spec.rb | 42 ++- spec/features/merge_requests/target_branch_spec.rb | 11 +- .../merge_requests/widget_deployments_spec.rb | 8 +- spec/features/merge_requests/widget_spec.rb | 33 +- .../api/schemas/entities/merge_request.json | 98 ++++++ .../api/schemas/entities/merge_request_basic.json | 14 + spec/helpers/merge_requests_helper_spec.rb | 192 ---------- spec/javascripts/commit/pipelines/mock_data.js | 1 + spec/javascripts/merge_request_widget_spec.js | 199 ----------- spec/javascripts/merged_buttons_spec.js | 44 --- spec/javascripts/test_bundle.js | 1 - .../components/mr_widget_author_spec.js | 39 +++ .../components/mr_widget_author_time_spec.js | 61 ++++ .../components/mr_widget_deployment_spec.js | 184 ++++++++++ .../components/mr_widget_header_spec.js | 95 +++++ .../components/mr_widget_merge_help_spec.js | 51 +++ .../components/mr_widget_pipeline_spec.js | 131 +++++++ .../components/mr_widget_related_links_spec.js | 138 ++++++++ .../components/states/mr_widget_archived_spec.js | 18 + .../states/mr_widget_auto_merge_failed_spec.js | 32 ++ .../components/states/mr_widget_checking_spec.js | 19 + .../components/states/mr_widget_closed_spec.js | 51 +++ .../components/states/mr_widget_conflicts_spec.js | 69 ++++ .../states/mr_widget_failed_to_merge_spec.js | 122 +++++++ .../components/states/mr_widget_locked_spec.js | 33 ++ .../mr_widget_merge_when_pipeline_succeeds_spec.js | 213 +++++++++++ .../components/states/mr_widget_merged_spec.js | 174 +++++++++ .../states/mr_widget_missing_branch_spec.js | 55 +++ .../states/mr_widget_not_allowed_spec.js | 17 + .../states/mr_widget_nothing_to_merge_spec.js | 17 + .../states/mr_widget_pipeline_blocked_spec.js | 16 + .../states/mr_widget_pipeline_failed_spec.js | 16 + .../states/mr_widget_ready_to_merge_spec.js | 389 +++++++++++++++++++++ .../mr_widget_unresolved_discussions_spec.js | 47 +++ .../components/states/mr_widget_wip_spec.js | 96 +++++ spec/javascripts/vue_mr_widget/mock_data.js | 214 ++++++++++++ .../vue_mr_widget/mr_widget_options_spec.js | 326 +++++++++++++++++ .../services/mr_widget_service_spec.js | 46 +++ .../vue_mr_widget/stores/get_state_key_spec.js | 62 ++++ spec/lib/gitlab/prometheus_spec.rb | 20 +- spec/models/deployment_spec.rb | 27 ++ .../project_services/prometheus_service_spec.rb | 23 +- spec/presenters/merge_request_presenter_spec.rb | 356 +++++++++++++++++++ spec/serializers/build_entity_spec.rb | 2 +- spec/serializers/build_serializer_spec.rb | 2 +- spec/serializers/deployment_entity_spec.rb | 2 +- spec/serializers/environment_serializer_spec.rb | 2 +- spec/serializers/event_entity_spec.rb | 13 + .../merge_request_basic_serializer_spec.rb | 12 + spec/serializers/merge_request_entity_spec.rb | 128 +++++++ spec/serializers/merge_request_serializer_spec.rb | 37 ++ spec/serializers/pipeline_entity_spec.rb | 4 +- spec/serializers/pipeline_serializer_spec.rb | 6 +- spec/serializers/stage_entity_spec.rb | 2 +- spec/support/prometheus_helpers.rb | 34 +- spec/support/wait_for_requests.rb | 8 +- spec/support/wait_for_vue_resource.rb | 14 +- 195 files changed, 7028 insertions(+), 1557 deletions(-) create mode 100644 app/assets/javascripts/lib/utils/simple_poll.js delete mode 100644 app/assets/javascripts/merge_request_widget/ci_bundle.js delete mode 100644 app/assets/javascripts/merged_buttons.js create mode 100644 app/assets/javascripts/pipelines/components/stage.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_locked.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/dependencies.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/event_hub.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/index.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js create mode 100644 app/assets/javascripts/vue_shared/components/memory_graph.js create mode 100644 app/assets/javascripts/vue_shared/components/pipeline_status_icon.js create mode 100644 app/assets/javascripts/vue_shared/pipeline_svg_icons.js create mode 100644 app/assets/stylesheets/framework/memory_graph.scss create mode 100644 app/presenters/merge_request_presenter.rb create mode 100644 app/serializers/event_entity.rb create mode 100644 app/serializers/merge_request_basic_entity.rb create mode 100644 app/serializers/merge_request_basic_serializer.rb delete mode 100644 app/views/projects/merge_requests/cancel_merge_when_pipeline_succeeds.js.haml delete mode 100644 app/views/projects/merge_requests/merge.js.haml delete mode 100644 app/views/projects/merge_requests/widget/_closed.html.haml create mode 100644 app/views/projects/merge_requests/widget/_commit_change_content.html.haml delete mode 100644 app/views/projects/merge_requests/widget/_heading.html.haml delete mode 100644 app/views/projects/merge_requests/widget/_locked.html.haml delete mode 100644 app/views/projects/merge_requests/widget/_merged.html.haml delete mode 100644 app/views/projects/merge_requests/widget/_merged_buttons.haml delete mode 100644 app/views/projects/merge_requests/widget/_open.html.haml delete mode 100644 app/views/projects/merge_requests/widget/_show.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_accept.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_archived.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_build_failed.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_check.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_conflicts.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_manual.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_merge_when_pipeline_succeeds.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_missing_branch.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_not_allowed.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_nothing.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_reload.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_sha_mismatch.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_unresolved_discussions.html.haml delete mode 100644 app/views/projects/merge_requests/widget/open/_wip.html.haml create mode 100644 spec/fixtures/api/schemas/entities/merge_request.json create mode 100644 spec/fixtures/api/schemas/entities/merge_request_basic.json delete mode 100644 spec/javascripts/merge_request_widget_spec.js delete mode 100644 spec/javascripts/merged_buttons_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js create mode 100644 spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js create mode 100644 spec/javascripts/vue_mr_widget/mock_data.js create mode 100644 spec/javascripts/vue_mr_widget/mr_widget_options_spec.js create mode 100644 spec/javascripts/vue_mr_widget/services/mr_widget_service_spec.js create mode 100644 spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js create mode 100644 spec/presenters/merge_request_presenter_spec.rb create mode 100644 spec/serializers/event_entity_spec.rb create mode 100644 spec/serializers/merge_request_basic_serializer_spec.rb create mode 100644 spec/serializers/merge_request_entity_spec.rb create mode 100644 spec/serializers/merge_request_serializer_spec.rb diff --git a/app/assets/javascripts/diff_notes/components/resolve_btn.js b/app/assets/javascripts/diff_notes/components/resolve_btn.js index 92f6fd654b3..9d51fb53eb2 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_btn.js +++ b/app/assets/javascripts/diff_notes/components/resolve_btn.js @@ -88,6 +88,7 @@ const ResolveBtn = Vue.extend({ CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolved_by); this.discussion.updateHeadline(data); + gl.mrWidget.checkStatus(); } else { new Flash(errorFlashMsg); } diff --git a/app/assets/javascripts/diff_notes/services/resolve.js b/app/assets/javascripts/diff_notes/services/resolve.js index 4ea6ba8a73d..ba4f6d36fcb 100644 --- a/app/assets/javascripts/diff_notes/services/resolve.js +++ b/app/assets/javascripts/diff_notes/services/resolve.js @@ -49,6 +49,7 @@ class ResolveServiceClass { discussion.resolveAllNotes(resolved_by); } + gl.mrWidget.checkStatus(); discussion.updateHeadline(data); } else { throw new Error('An error occurred when trying to resolve discussion.'); diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index bf802056d36..abb871c3af0 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -10,7 +10,6 @@ /* global IssuableForm */ /* global LabelsSelect */ /* global MilestoneSelect */ -/* global MergedButtons */ /* global Commit */ /* global NotificationsForm */ /* global TreeView */ @@ -216,15 +215,10 @@ const ShortcutsBlob = require('./shortcuts_blob'); new gl.Diff(); shortcut_handler = new ShortcutsIssuable(true); new ZenMode(); - new MergedButtons(); - break; - case 'projects:merge_requests:commits': - new MergedButtons(); break; case "projects:merge_requests:diffs": new gl.Diff(); new ZenMode(); - new MergedButtons(); break; case 'dashboard:activity': new gl.Activities(); diff --git a/app/assets/javascripts/lib/utils/simple_poll.js b/app/assets/javascripts/lib/utils/simple_poll.js new file mode 100644 index 00000000000..25ca98afbe7 --- /dev/null +++ b/app/assets/javascripts/lib/utils/simple_poll.js @@ -0,0 +1,15 @@ +export default (fn, interval = 2000, timeout = 60000) => { + const startTime = Date.now(); + + return new Promise((resolve, reject) => { + const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg)); + const next = () => { + if (Date.now() - startTime < timeout) { + setTimeout(fn.bind(null, next, stop), interval); + } else { + reject(new Error('SIMPLE_POLL_TIMEOUT')); + } + }; + fn(next, stop); + }); +}; diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 1b0d5fc92e3..a07aa047293 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -123,8 +123,6 @@ import './member_expiration_date'; import './members'; import './merge_request'; import './merge_request_tabs'; -import './merge_request_widget'; -import './merged_buttons'; import './milestone'; import './milestone_select'; import './mini_pipeline_graph_dropdown'; diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 5e01aacf2ba..ed342b9990f 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -106,6 +106,21 @@ require('./merge_request_tabs'); }); }; + MergeRequest.prototype.updateStatusText = function(classToRemove, classToAdd, newStatusText) { + $('.detail-page-header .status-box') + .removeClass(classToRemove) + .addClass(classToAdd) + .find('span') + .text(newStatusText); + }; + + MergeRequest.prototype.decreaseCounter = function(by = 1) { + const $el = $('.nav-links .js-merge-counter'); + const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0); + + $el.text(gl.text.addDelimiter(count)); + }; + return MergeRequest; })(); }).call(window); diff --git a/app/assets/javascripts/merge_request_widget/ci_bundle.js b/app/assets/javascripts/merge_request_widget/ci_bundle.js deleted file mode 100644 index 21d7c3e168e..00000000000 --- a/app/assets/javascripts/merge_request_widget/ci_bundle.js +++ /dev/null @@ -1,53 +0,0 @@ -/* global merge_request_widget */ - -(() => { - $(() => { - /* TODO: This needs a better home, or should be refactored. It was previously contained - * in a script tag in app/views/projects/merge_requests/widget/open/_accept.html.haml, - * but Vue chokes on script tags and prevents their execution. So it was moved here - * temporarily. - * */ - - $(document) - .off('ajax:send', '.accept-mr-form') - .on('ajax:send', '.accept-mr-form', () => { - $('.accept-mr-form :input').disable(); - }); - - $(document) - .off('click', '.accept-merge-request') - .on('click', '.accept-merge-request', () => { - $('.js-merge-button, .js-merge-when-pipeline-succeeds-button').html(' Merge in progress'); - }); - - $(document) - .off('click', '.merge-when-pipeline-succeeds') - .on('click', '.merge-when-pipeline-succeeds', () => { - $('#merge_when_pipeline_succeeds').val('1'); - }); - - $(document) - .off('click', '.js-merge-dropdown a') - .on('click', '.js-merge-dropdown a', (e) => { - e.preventDefault(); - $(e.target).closest('form').submit(); - }); - if ($('.rebase-in-progress').length) { - merge_request_widget.rebaseInProgress(); - } else if ($('.rebase-mr-form').length) { - $(document) - .off('ajax:send', '.rebase-mr-form') - .on('ajax:send', '.rebase-mr-form', () => { - $('.rebase-mr-form :input').disable(); - }); - - $(document) - .off('click', '.js-rebase-button') - .on('click', '.js-rebase-button', () => { - $('.js-rebase-button').html(" Rebase in progress"); - }); - } else { - setTimeout(() => merge_request_widget.getMergeStatus(), 200); - } - }); -})(); diff --git a/app/assets/javascripts/merged_buttons.js b/app/assets/javascripts/merged_buttons.js deleted file mode 100644 index 7b0997c6520..00000000000 --- a/app/assets/javascripts/merged_buttons.js +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, max-len */ - -import '~/lib/utils/url_utility'; - -(function() { - this.MergedButtons = (function() { - function MergedButtons() { - this.removeSourceBranch = this.removeSourceBranch.bind(this); - this.removeBranchSuccess = this.removeBranchSuccess.bind(this); - this.removeBranchError = this.removeBranchError.bind(this); - this.$removeBranchWidget = $('.remove_source_branch_widget'); - this.$removeBranchProgress = $('.remove_source_branch_in_progress'); - this.$removeBranchFailed = $('.remove_source_branch_widget.failed'); - this.cleanEventListeners(); - this.initEventListeners(); - } - - MergedButtons.prototype.cleanEventListeners = function() { - $(document).off('click', '.remove_source_branch'); - $(document).off('ajax:success', '.remove_source_branch'); - return $(document).off('ajax:error', '.remove_source_branch'); - }; - - MergedButtons.prototype.initEventListeners = function() { - $(document).on('click', '.remove_source_branch', this.removeSourceBranch); - $(document).on('ajax:success', '.remove_source_branch', this.removeBranchSuccess); - $(document).on('ajax:error', '.remove_source_branch', this.removeBranchError); - }; - - MergedButtons.prototype.removeSourceBranch = function() { - this.$removeBranchWidget.hide(); - return this.$removeBranchProgress.show(); - }; - - MergedButtons.prototype.removeBranchSuccess = function() { - gl.utils.refreshCurrentPage(); - }; - - MergedButtons.prototype.removeBranchError = function() { - this.$removeBranchWidget.hide(); - this.$removeBranchProgress.hide(); - return this.$removeBranchFailed.show(); - }; - - return MergedButtons; - })(); -}).call(window); diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 55391ebc089..d2e602a0763 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -276,7 +276,7 @@ const normalizeNewlines = function(str) { var votesBlock; if (noteEntity.commands_changes) { if ('merge' in noteEntity.commands_changes) { - $.get(mrRefreshWidgetUrl); + Notes.checkMergeRequestStatus(); } if ('emoji_award' in noteEntity.commands_changes) { @@ -424,6 +424,7 @@ const normalizeNewlines = function(str) { } gl.utils.localTimeAgo($('.js-timeago'), false); + Notes.checkMergeRequestStatus(); return this.updateNotesCount(1); }; @@ -769,7 +770,8 @@ const normalizeNewlines = function(str) { } }; })(this)); - // Decrement the "Discussions" counter only once + + Notes.checkMergeRequestStatus(); return this.updateNotesCount(-1); }; @@ -1115,6 +1117,12 @@ const normalizeNewlines = function(str) { return $form; }; + Notes.checkMergeRequestStatus = function() { + if (gl.utils.getPagePath(1) === 'merge_requests') { + gl.mrWidget.checkStatus(); + } + }; + Notes.animateAppendNote = function(noteHtml, $notesList) { const $note = $(noteHtml); diff --git a/app/assets/javascripts/pipelines/components/stage.js b/app/assets/javascripts/pipelines/components/stage.js new file mode 100644 index 00000000000..034e8d3280e --- /dev/null +++ b/app/assets/javascripts/pipelines/components/stage.js @@ -0,0 +1,104 @@ +/* global Flash */ +import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons'; + +export default { + data() { + return { + builds: '', + spinner: '', + }; + }, + + props: { + stage: { + type: Object, + required: true, + }, + }, + + updated() { + if (this.builds) { + this.stopDropdownClickPropagation(); + } + }, + + methods: { + fetchBuilds(e) { + const ariaExpanded = e.currentTarget.attributes['aria-expanded']; + + if (ariaExpanded && (ariaExpanded.textContent === 'true')) return null; + + return this.$http.get(this.stage.dropdown_path) + .then((response) => { + this.builds = JSON.parse(response.body).html; + }, () => { + const flash = new Flash('Something went wrong on our end.'); + return flash; + }); + }, + + /** + * When the user right clicks or cmd/ctrl + click in the job name + * the dropdown should not be closed and the link should open in another tab, + * so we stop propagation of the click event inside the dropdown. + * + * Since this component is rendered multiple times per page we need to guarantee we only + * target the click event of this component. + */ + stopDropdownClickPropagation() { + $(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item')).on('click', (e) => { + e.stopPropagation(); + }); + }, + }, + computed: { + buildsOrSpinner() { + return this.builds ? this.builds : this.spinner; + }, + dropdownClass() { + if (this.builds) return 'js-builds-dropdown-container'; + return 'js-builds-dropdown-loading builds-dropdown-loading'; + }, + buildStatus() { + return `Build: ${this.stage.status.label}`; + }, + tooltip() { + return `has-tooltip ci-status-icon ci-status-icon-${this.stage.status.group}`; + }, + triggerButtonClass() { + return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`; + }, + svgHTML() { + return borderlessStatusIconEntityMap[this.stage.status.icon]; + }, + }, + watch: { + 'stage.title': function stageTitle() { + $(this.$refs.button).tooltip('destroy').tooltip(); + }, + }, + template: ` +
+ + +
+ `, +}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js new file mode 100644 index 00000000000..a01cb8cc202 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js @@ -0,0 +1,23 @@ +export default { + name: 'MRWidgetAuthor', + props: { + author: { type: Object, required: true }, + showAuthorName: { type: Boolean, required: false, default: true }, + showAuthorTooltip: { type: Boolean, required: false, default: false }, + }, + template: ` + + + {{author.name}} + + + `, +}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js new file mode 100644 index 00000000000..6d2ed5fda64 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js @@ -0,0 +1,27 @@ +import MRWidgetAuthor from './mr_widget_author'; + +export default { + name: 'MRWidgetAuthorTime', + props: { + actionText: { type: String, required: true }, + author: { type: Object, required: true }, + dateTitle: { type: String, required: true }, + dateReadable: { type: String, required: true }, + }, + components: { + 'mr-widget-author': MRWidgetAuthor, + }, + template: ` +

+ {{actionText}} + + +

+ `, +}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js new file mode 100644 index 00000000000..630e80a7408 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js @@ -0,0 +1,118 @@ +/* global Flash */ + +import '~/lib/utils/datetime_utility'; +import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons'; +import MemoryUsage from './mr_widget_memory_usage'; +import MRWidgetService from '../services/mr_widget_service'; + +export default { + name: 'MRWidgetDeployment', + props: { + mr: { type: Object, required: true }, + service: { type: Object, required: true }, + }, + components: { + 'mr-widget-memory-usage': MemoryUsage, + }, + computed: { + svg() { + return statusClassToSvgMap.icon_status_success; + }, + }, + methods: { + formatDate(date) { + return gl.utils.getTimeago().format(date); + }, + hasExternalUrls(deployment = {}) { + return deployment.external_url && deployment.external_url_formatted; + }, + hasDeploymentTime(deployment = {}) { + return deployment.deployed_at && deployment.deployed_at_formatted; + }, + hasDeploymentMeta(deployment = {}) { + return deployment.url && deployment.name; + }, + stopEnvironment(deployment) { + const msg = 'Are you sure you want to stop this environment?'; + const isConfirmed = confirm(msg); // eslint-disable-line + + if (isConfirmed) { + MRWidgetService.stopEnvironment(deployment.stop_url) + .then(res => res.json()) + .then((res) => { + if (res.redirect_url) { + gl.utils.visitUrl(res.redirect_url); + } + }) + .catch(() => { + new Flash('Something went wrong while stopping this environment. Please try again.'); // eslint-disable-line + }); + } + }, + }, + template: ` +
+
+
+
+ + + +
+ + + Deployed to + + + {{deployment.name}} + + + on + + +