Commit cc59848b authored by Nick Thomas's avatar Nick Thomas

Merge remote-tracking branch 'upstream/master' into ce-to-ee

parents f5fd172d 407d8af4
...@@ -19,11 +19,11 @@ ...@@ -19,11 +19,11 @@
* Please refer to this [comment](https://gitlab.com/gitlab-org/gitlab-ee/issues/1589#note_23630610) * Please refer to this [comment](https://gitlab.com/gitlab-org/gitlab-ee/issues/1589#note_23630610)
* for more information * for more information
*/ */
import statusCodes from '~/lib/utils/http_status'; import Visibility from 'visibilityjs';
import '~/flash';
import '~/lib/utils/common_utils';
import deployBoardSvg from 'empty_states/icons/_deploy_board.svg'; import deployBoardSvg from 'empty_states/icons/_deploy_board.svg';
import instanceComponent from './deploy_board_instance_component.vue'; import instanceComponent from './deploy_board_instance_component.vue';
import Poll from '../../lib/utils/poll';
import '../../flash';
export default { export default {
...@@ -62,73 +62,45 @@ export default { ...@@ -62,73 +62,45 @@ export default {
return { return {
isLoading: false, isLoading: false,
hasError: false, hasError: false,
backOffRequestCounter: 0,
deployBoardSvg, deployBoardSvg,
}; };
}, },
created() { created() {
this.getDeployBoard(true); const poll = new Poll({
}, resource: this.service,
method: 'getDeployBoard',
updated() { data: this.endpoint,
// While board is not complete we need to request new data from the server. successCallback: this.successCallback,
// Let's make sure we are not making any request at the moment errorCallback: this.errorCallback,
// and that we only make this request if the latest response was not 204. });
if (!this.isLoading &&
!this.hasError && if (!Visibility.hidden()) {
this.deployBoardData.completion && this.isLoading = true;
this.deployBoardData.completion < 100) { poll.makeRequest();
// let's wait 1s and make the request again
setTimeout(() => {
this.getDeployBoard(false);
}, 3000);
} }
Visibility.change(() => {
if (!Visibility.hidden()) {
poll.restart();
} else {
poll.stop();
}
});
}, },
methods: { methods: {
getDeployBoard(showLoading) { successCallback(response) {
this.isLoading = showLoading; const data = response.json();
const maxNumberOfRequests = 3; this.store.storeDeployBoard(this.environmentID, data);
this.isLoading = false;
// If the response is 204, we make 3 more requests. },
gl.utils.backOff((next, stop) => {
this.service.getDeployBoard(this.endpoint) errorCallback() {
.then((resp) => { this.isLoading = false;
if (resp.status === statusCodes.NO_CONTENT) { // eslint-disable-next-line no-new
this.backOffRequestCounter = this.backOffRequestCounter += 1; new Flash('An error occurred while fetching the deploy board.');
if (this.backOffRequestCounter < maxNumberOfRequests) {
next();
} else {
stop(resp);
}
} else {
stop(resp);
}
})
.catch(stop);
})
.then((resp) => {
if (resp.status === statusCodes.NO_CONTENT) {
this.hasError = true;
return resp;
}
return resp.json();
})
.then((response) => {
this.store.storeDeployBoard(this.environmentID, response);
return response;
})
.then(() => {
this.isLoading = false;
})
.catch(() => {
this.isLoading = false;
new Flash('An error occurred while fetching the deploy board.', 'alert');
});
}, },
}, },
......
...@@ -1484,6 +1484,9 @@ class Project < ActiveRecord::Base ...@@ -1484,6 +1484,9 @@ class Project < ActiveRecord::Base
else else
update_attribute(name, value) update_attribute(name, value)
end end
rescue ActiveRecord::RecordNotSaved => e
handle_update_attribute_error(e, value)
end end
def change_repository_storage(new_repository_storage_key) def change_repository_storage(new_repository_storage_key)
...@@ -1645,4 +1648,16 @@ class Project < ActiveRecord::Base ...@@ -1645,4 +1648,16 @@ class Project < ActiveRecord::Base
ContainerRepository.build_root_repository(self).has_tags? ContainerRepository.build_root_repository(self).has_tags?
end end
def handle_update_attribute_error(ex, value)
if ex.message.start_with?('Failed to replace')
if value.respond_to?(:each)
invalid = value.detect(&:invalid?)
raise ex, ([ex.message] + invalid.errors.full_messages).join(' ') if invalid
end
end
raise ex
end
end end
...@@ -3,14 +3,24 @@ ...@@ -3,14 +3,24 @@
require 'rubygems' require 'rubygems'
require 'bundler/setup' require 'bundler/setup'
require 'json' require 'json'
require 'active_model'
require 'active_support' require 'active_support'
require 'active_support/core_ext' require 'active_support/core_ext'
require 'benchmark' require 'benchmark'
$: << File.expand_path('../lib', File.dirname(__FILE__)) $: << File.expand_path('../lib', File.dirname(__FILE__))
require 'linguist'
require 'open3'
require 'rugged'
require 'gitlab/elastic/client' require 'gitlab/elastic/client'
require 'elasticsearch/model'
require 'elasticsearch/git' require 'elasticsearch/git'
require 'elasticsearch/git/encoder_helper'
require 'elasticsearch/git/lite_blob'
require 'elasticsearch/git/model'
require 'elasticsearch/git/repository'
Thread.abort_on_exception = true Thread.abort_on_exception = true
......
---
title: Uses etag polling for deployboards
merge_request: 1713
author:
---
title: Add missing project attributes to Import/Export
merge_request:
author:
require "elasticsearch/git/model"
require "elasticsearch/git/repository"
module Elasticsearch module Elasticsearch
module Git module Git
end end
......
require 'active_support/concern'
require 'charlock_holmes'
module Elasticsearch module Elasticsearch
module Git module Git
module EncoderHelper module EncoderHelper
......
require 'linguist'
require 'elasticsearch/git/encoder_helper'
module Elasticsearch module Elasticsearch
module Git module Git
class LiteBlob class LiteBlob
......
require 'active_support/concern'
require 'active_model'
require 'elasticsearch/model'
module Elasticsearch module Elasticsearch
module Git module Git
module Model module Model
......
require 'active_support/concern'
require 'active_model'
require 'elasticsearch'
require 'elasticsearch/git/model'
require 'elasticsearch/git/encoder_helper'
require 'elasticsearch/git/lite_blob'
require 'rugged'
require 'open3'
module Elasticsearch module Elasticsearch
module Git module Git
module Repository module Repository
......
...@@ -41,7 +41,6 @@ project_tree: ...@@ -41,7 +41,6 @@ project_tree:
- :statuses - :statuses
- triggers: - triggers:
- :trigger_schedule - :trigger_schedule
- :deploy_keys
- :services - :services
- :hooks - :hooks
- protected_branches: - protected_branches:
...@@ -53,10 +52,6 @@ project_tree: ...@@ -53,10 +52,6 @@ project_tree:
# Only include the following attributes for the models specified. # Only include the following attributes for the models specified.
included_attributes: included_attributes:
project:
- :description
- :visibility_level
- :archived
user: user:
- :id - :id
- :email - :email
...@@ -66,6 +61,34 @@ included_attributes: ...@@ -66,6 +61,34 @@ included_attributes:
# Do not include the following attributes for the models specified. # Do not include the following attributes for the models specified.
excluded_attributes: excluded_attributes:
project:
- :name
- :path
- :namespace_id
- :creator_id
- :import_url
- :import_status
- :avatar
- :import_type
- :import_source
- :import_error
- :mirror
- :runners_token
- :repository_storage
- :repository_read_only
- :lfs_enabled
- :import_jid
- :created_at
- :updated_at
- :import_jid
- :import_jid
- :id
- :star_count
- :last_activity_at
- :mirror_last_update_at
- :mirror_last_successful_update_at
- :mirror_user_id
- :mirror_trigger_builds
snippets: snippets:
- :expired_at - :expired_at
merge_request_diff: merge_request_diff:
...@@ -94,3 +117,5 @@ methods: ...@@ -94,3 +117,5 @@ methods:
- :utf8_st_diffs - :utf8_st_diffs
merge_requests: merge_requests:
- :diff_head_sha - :diff_head_sha
project:
- :description_html
\ No newline at end of file
...@@ -71,14 +71,14 @@ module Gitlab ...@@ -71,14 +71,14 @@ module Gitlab
def restore_project def restore_project
return @project unless @tree_hash return @project unless @tree_hash
@project.update(project_params) @project.update_columns(project_params)
@project @project
end end
def project_params def project_params
@tree_hash.reject do |key, value| @tree_hash.reject do |key, value|
# return params that are not 1 to many or 1 to 1 relations # return params that are not 1 to many or 1 to 1 relations
value.is_a?(Array) || key == key.singularize value.respond_to?(:each) && !Project.column_names.include?(key)
end end
end end
......
...@@ -15,7 +15,10 @@ module Gitlab ...@@ -15,7 +15,10 @@ module Gitlab
# Outputs a hash in the format described here: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html # Outputs a hash in the format described here: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
# for outputting a project in JSON format, including its relations and sub relations. # for outputting a project in JSON format, including its relations and sub relations.
def project_tree def project_tree
@attributes_finder.find_included(:project).merge(include: build_hash(@tree)) attributes = @attributes_finder.find(:project)
project_attributes = attributes.is_a?(Hash) ? attributes[:project] : {}
project_attributes.merge(include: build_hash(@tree))
rescue => e rescue => e
@shared.error(e) @shared.error(e)
false false
......
...@@ -55,10 +55,12 @@ feature 'Issue Sidebar', feature: true do ...@@ -55,10 +55,12 @@ feature 'Issue Sidebar', feature: true do
# Resize the window # Resize the window
resize_screen_sm resize_screen_sm
# Make sure the sidebar is collapsed # Make sure the sidebar is collapsed
find(sidebar_selector)
expect(page).to have_css(sidebar_selector) expect(page).to have_css(sidebar_selector)
# Once is collapsed let's open the sidebard and reload # Once is collapsed let's open the sidebard and reload
open_issue_sidebar open_issue_sidebar
refresh refresh
find(sidebar_selector)
expect(page).to have_css(sidebar_selector) expect(page).to have_css(sidebar_selector)
# Restore the window size as it was including the sidebar # Restore the window size as it was including the sidebar
restore_window_size restore_window_size
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
"description": "Nisi et repellendus ut enim quo accusamus vel magnam.", "description": "Nisi et repellendus ut enim quo accusamus vel magnam.",
"visibility_level": 10, "visibility_level": 10,
"archived": false, "archived": false,
"description_html": "description",
"labels": [ "labels": [
{ {
"id": 2, "id": 2,
......
...@@ -30,6 +30,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do ...@@ -30,6 +30,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::ENABLED) expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::ENABLED)
end end
it 'has the project html description' do
expect(Project.find_by_path('project').description_html).to eq('description')
end
it 'has the same label associated to two issues' do it 'has the same label associated to two issues' do
expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2) expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2)
end end
......
...@@ -6,7 +6,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do ...@@ -6,7 +6,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) } let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { setup_project } let!(:project) { setup_project }
before do before do
project.team << [user, :master] project.team << [user, :master]
...@@ -189,6 +189,16 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do ...@@ -189,6 +189,16 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
end end
end end
end end
context 'project attributes' do
it 'contains the html description' do
expect(saved_project_json).to include("description_html" => 'description')
end
it 'does not contain the runners token' do
expect(saved_project_json).not_to include("runners_token" => 'token')
end
end
end end
end end
...@@ -209,6 +219,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do ...@@ -209,6 +219,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
releases: [release], releases: [release],
group: group group: group
) )
project.update_column(:description_html, 'description')
project_label = create(:label, project: project) project_label = create(:label, project: project)
group_label = create(:group_label, group: group) group_label = create(:group_label, group: group)
create(:label_link, label: project_label, target: issue) create(:label_link, label: project_label, target: issue)
......
...@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::Reader, lib: true do ...@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::Reader, lib: true do
let(:test_config) { 'spec/support/import_export/import_export.yml' } let(:test_config) { 'spec/support/import_export/import_export.yml' }
let(:project_tree_hash) do let(:project_tree_hash) do
{ {
only: [:name, :path], except: [:id, :created_at],
include: [:issues, :labels, include: [:issues, :labels,
{ merge_requests: { { merge_requests: {
only: [:id], only: [:id],
......
...@@ -333,6 +333,37 @@ Project: ...@@ -333,6 +333,37 @@ Project:
- snippets_enabled - snippets_enabled
- visibility_level - visibility_level
- archived - archived
- created_at
- updated_at
- last_activity_at
- star_count
- ci_id
- shared_runners_enabled
- build_coverage_regex
- build_allow_git_fetchs
- build_timeout
- pending_delete
- public_builds
- last_repository_check_failed
- last_repository_check_at
- container_registry_enabled
- only_allow_merge_if_pipeline_succeeds
- has_external_issue_tracker
- request_access_enabled
- has_external_wiki
- only_allow_merge_if_all_discussions_are_resolved
- auto_cancel_pending_pipelines
- printing_merge_request_link_enabled
- build_allow_git_fetch
- merge_requests_template
- merge_requests_rebase_enabled
- approvals_before_merge
- reset_approvals_on_push
- merge_requests_ff_only_enabled
- issues_template
- repository_size_limit
- sync_time
- service_desk_enabled
Author: Author:
- name - name
ProjectFeature: ProjectFeature:
......
...@@ -2321,4 +2321,23 @@ describe Project, models: true do ...@@ -2321,4 +2321,23 @@ describe Project, models: true do
expect(project.pipeline_status).to be_loaded expect(project.pipeline_status).to be_loaded
end end
end end
describe '#append_or_update_attribute' do
let(:project) { create(:project) }
it 'shows full error updating an invalid MR' do
error_message = 'Failed to replace merge_requests because one or more of the new records could not be saved.'\
' Validate fork Source project is not a fork of the target project'
expect { project.append_or_update_attribute(:merge_requests, [create(:merge_request)]) }.
to raise_error(ActiveRecord::RecordNotSaved, error_message)
end
it 'updates the project succesfully' do
merge_request = create(:merge_request, target_project: project, source_project: project)
expect { project.append_or_update_attribute(:merge_requests, [merge_request]) }.
not_to raise_error
end
end
end end
...@@ -11,9 +11,6 @@ project_tree: ...@@ -11,9 +11,6 @@ project_tree:
- :user - :user
included_attributes: included_attributes:
project:
- :name
- :path
merge_requests: merge_requests:
- :id - :id
user: user:
...@@ -21,4 +18,7 @@ included_attributes: ...@@ -21,4 +18,7 @@ included_attributes:
excluded_attributes: excluded_attributes:
merge_requests: merge_requests:
- :iid - :iid
\ No newline at end of file project:
- :id
- :created_at
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment