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 @@
* Please refer to this [comment](https://gitlab.com/gitlab-org/gitlab-ee/issues/1589#note_23630610)
* for more information
*/
import statusCodes from '~/lib/utils/http_status';
import '~/flash';
import '~/lib/utils/common_utils';
import Visibility from 'visibilityjs';
import deployBoardSvg from 'empty_states/icons/_deploy_board.svg';
import instanceComponent from './deploy_board_instance_component.vue';
import Poll from '../../lib/utils/poll';
import '../../flash';
export default {
......@@ -62,73 +62,45 @@ export default {
return {
isLoading: false,
hasError: false,
backOffRequestCounter: 0,
deployBoardSvg,
};
},
created() {
this.getDeployBoard(true);
},
updated() {
// While board is not complete we need to request new data from the server.
// Let's make sure we are not making any request at the moment
// and that we only make this request if the latest response was not 204.
if (!this.isLoading &&
!this.hasError &&
this.deployBoardData.completion &&
this.deployBoardData.completion < 100) {
// let's wait 1s and make the request again
setTimeout(() => {
this.getDeployBoard(false);
}, 3000);
const poll = new Poll({
resource: this.service,
method: 'getDeployBoard',
data: this.endpoint,
successCallback: this.successCallback,
errorCallback: this.errorCallback,
});
if (!Visibility.hidden()) {
this.isLoading = true;
poll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
poll.restart();
} else {
poll.stop();
}
});
},
methods: {
getDeployBoard(showLoading) {
this.isLoading = showLoading;
const maxNumberOfRequests = 3;
// If the response is 204, we make 3 more requests.
gl.utils.backOff((next, stop) => {
this.service.getDeployBoard(this.endpoint)
.then((resp) => {
if (resp.status === statusCodes.NO_CONTENT) {
this.backOffRequestCounter = this.backOffRequestCounter += 1;
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');
});
successCallback(response) {
const data = response.json();
this.store.storeDeployBoard(this.environmentID, data);
this.isLoading = false;
},
errorCallback() {
this.isLoading = false;
// eslint-disable-next-line no-new
new Flash('An error occurred while fetching the deploy board.');
},
},
......
......@@ -1484,6 +1484,9 @@ class Project < ActiveRecord::Base
else
update_attribute(name, value)
end
rescue ActiveRecord::RecordNotSaved => e
handle_update_attribute_error(e, value)
end
def change_repository_storage(new_repository_storage_key)
......@@ -1645,4 +1648,16 @@ class Project < ActiveRecord::Base
ContainerRepository.build_root_repository(self).has_tags?
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
......@@ -3,14 +3,24 @@
require 'rubygems'
require 'bundler/setup'
require 'json'
require 'active_model'
require 'active_support'
require 'active_support/core_ext'
require 'benchmark'
$: << File.expand_path('../lib', File.dirname(__FILE__))
require 'linguist'
require 'open3'
require 'rugged'
require 'gitlab/elastic/client'
require 'elasticsearch/model'
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
......
---
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 Git
end
......
require 'active_support/concern'
require 'charlock_holmes'
module Elasticsearch
module Git
module EncoderHelper
......
require 'linguist'
require 'elasticsearch/git/encoder_helper'
module Elasticsearch
module Git
class LiteBlob
......
require 'active_support/concern'
require 'active_model'
require 'elasticsearch/model'
module Elasticsearch
module Git
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 Git
module Repository
......
......@@ -41,7 +41,6 @@ project_tree:
- :statuses
- triggers:
- :trigger_schedule
- :deploy_keys
- :services
- :hooks
- protected_branches:
......@@ -53,10 +52,6 @@ project_tree:
# Only include the following attributes for the models specified.
included_attributes:
project:
- :description
- :visibility_level
- :archived
user:
- :id
- :email
......@@ -66,6 +61,34 @@ included_attributes:
# Do not include the following attributes for the models specified.
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:
- :expired_at
merge_request_diff:
......@@ -94,3 +117,5 @@ methods:
- :utf8_st_diffs
merge_requests:
- :diff_head_sha
project:
- :description_html
\ No newline at end of file
......@@ -71,14 +71,14 @@ module Gitlab
def restore_project
return @project unless @tree_hash
@project.update(project_params)
@project.update_columns(project_params)
@project
end
def project_params
@tree_hash.reject do |key, value|
# 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
......
......@@ -15,7 +15,10 @@ module Gitlab
# 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.
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
@shared.error(e)
false
......
......@@ -55,10 +55,12 @@ feature 'Issue Sidebar', feature: true do
# Resize the window
resize_screen_sm
# Make sure the sidebar is collapsed
find(sidebar_selector)
expect(page).to have_css(sidebar_selector)
# Once is collapsed let's open the sidebard and reload
open_issue_sidebar
refresh
find(sidebar_selector)
expect(page).to have_css(sidebar_selector)
# Restore the window size as it was including the sidebar
restore_window_size
......
......@@ -2,6 +2,7 @@
"description": "Nisi et repellendus ut enim quo accusamus vel magnam.",
"visibility_level": 10,
"archived": false,
"description_html": "description",
"labels": [
{
"id": 2,
......
......@@ -30,6 +30,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::ENABLED)
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
expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2)
end
......
......@@ -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(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:user) { create(:user) }
let(:project) { setup_project }
let!(:project) { setup_project }
before do
project.team << [user, :master]
......@@ -189,6 +189,16 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
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
......@@ -209,6 +219,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
releases: [release],
group: group
)
project.update_column(:description_html, 'description')
project_label = create(:label, project: project)
group_label = create(:group_label, group: group)
create(:label_link, label: project_label, target: issue)
......
......@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::Reader, lib: true do
let(:test_config) { 'spec/support/import_export/import_export.yml' }
let(:project_tree_hash) do
{
only: [:name, :path],
except: [:id, :created_at],
include: [:issues, :labels,
{ merge_requests: {
only: [:id],
......
......@@ -333,6 +333,37 @@ Project:
- snippets_enabled
- visibility_level
- 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:
- name
ProjectFeature:
......
......@@ -2321,4 +2321,23 @@ describe Project, models: true do
expect(project.pipeline_status).to be_loaded
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
......@@ -11,9 +11,6 @@ project_tree:
- :user
included_attributes:
project:
- :name
- :path
merge_requests:
- :id
user:
......@@ -21,4 +18,7 @@ included_attributes:
excluded_attributes:
merge_requests:
- :iid
\ No newline at end of file
- :iid
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