Commit 0a73bfba authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 76b43d8a 00112e67
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale';
import {
WEBIDE_MARK_APP_START,
......@@ -29,15 +30,17 @@ export default {
components: {
IdeSidebar,
RepoEditor,
'error-message': () => import('./error_message.vue'),
'gl-button': () => import('@gitlab/ui/src/components/base/button/button.vue'),
'gl-loading-icon': () => import('@gitlab/ui/src/components/base/loading_icon/loading_icon.vue'),
'commit-editor-header': () => import('./commit_sidebar/editor_header.vue'),
'repo-tabs': () => import('./repo_tabs.vue'),
'ide-status-bar': () => import('./ide_status_bar.vue'),
'find-file': () => import('~/vue_shared/components/file_finder/index.vue'),
'right-pane': () => import('./panes/right.vue'),
'new-modal': () => import('./new_dropdown/modal.vue'),
GlButton,
GlLoadingIcon,
ErrorMessage: () => import(/* webpackChunkName: 'ide_runtime' */ './error_message.vue'),
CommitEditorHeader: () =>
import(/* webpackChunkName: 'ide_runtime' */ './commit_sidebar/editor_header.vue'),
RepoTabs: () => import(/* webpackChunkName: 'ide_runtime' */ './repo_tabs.vue'),
IdeStatusBar: () => import(/* webpackChunkName: 'ide_runtime' */ './ide_status_bar.vue'),
FindFile: () =>
import(/* webpackChunkName: 'ide_runtime' */ '~/vue_shared/components/file_finder/index.vue'),
RightPane: () => import(/* webpackChunkName: 'ide_runtime' */ './panes/right.vue'),
NewModal: () => import(/* webpackChunkName: 'ide_runtime' */ './new_dropdown/modal.vue'),
},
mixins: [glFeatureFlagsMixin()],
data() {
......
......@@ -14,8 +14,10 @@ export default {
ResizablePanel,
ActivityBar,
IdeTree,
[leftSidebarViews.review.name]: () => import('./ide_review.vue'),
[leftSidebarViews.commit.name]: () => import('./repo_commit_section.vue'),
[leftSidebarViews.review.name]: () =>
import(/* webpackChunkName: 'ide_runtime' */ './ide_review.vue'),
[leftSidebarViews.commit.name]: () =>
import(/* webpackChunkName: 'ide_runtime' */ './repo_commit_section.vue'),
CommitForm,
IdeProjectHeader,
},
......
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import EmptyState from './empty_state.vue';
import TerminalSession from './session.vue';
export default {
components: {
EmptyState,
TerminalSession,
TerminalSession: () => import(/* webpackChunkName: 'ide_terminal' */ './session.vue'),
},
computed: {
...mapState('terminal', ['isShowSplash', 'paths']),
......
......@@ -52,7 +52,7 @@ class ProjectRepositoryStorageMove < ApplicationRecord
begin
storage_move.project.set_repository_read_only!(skip_git_transfer_check: true)
rescue => err
errors.add(:project, err.message)
storage_move.errors.add(:project, err.message)
next false
end
......
......@@ -16,6 +16,8 @@ module Packages
composer_json: composer_json
})
end
created_package
end
private
......
......@@ -12,7 +12,7 @@ module Packages
end
def execute
package.package_files.create!(
package_file = package.package_files.build(
file: file,
size: params['file.size'],
file_name: params[:file_name],
......@@ -25,6 +25,13 @@ module Packages
conan_file_type: params[:conan_file_type]
}
)
if params[:build].present?
package_file.package_file_build_infos << package_file.package_file_build_infos.build(pipeline: params[:build].pipeline)
end
package_file.save!
package_file
end
end
end
......
......@@ -8,9 +8,9 @@ module Packages
project
.packages
.with_package_type(package_type)
.safe_find_or_create_by!(name: name, version: version) do |pkg|
pkg.creator = package_creator
yield pkg if block_given?
.safe_find_or_create_by!(name: name, version: version) do |package|
package.creator = package_creator
add_build_info(package)
end
end
......@@ -18,7 +18,9 @@ module Packages
project
.packages
.with_package_type(package_type)
.create!(package_attrs(attrs))
.create!(package_attrs(attrs)) do |package|
add_build_info(package)
end
end
private
......@@ -34,5 +36,11 @@ module Packages
def package_creator
current_user if current_user.is_a?(User)
end
def add_build_info(package)
if params[:build].present?
package.build_infos.new(pipeline: params[:build].pipeline)
end
end
end
end
......@@ -18,9 +18,12 @@ module Packages
build: params[:build]
}
::Packages::Generic::FindOrCreatePackageService
package = ::Packages::Generic::FindOrCreatePackageService
.new(project, current_user, package_params)
.execute
package.build_infos.safe_find_or_create_by!(pipeline: params[:build].pipeline) if params[:build].present?
package
end
def create_package_file(package)
......
......@@ -4,11 +4,7 @@ module Packages
module Generic
class FindOrCreatePackageService < ::Packages::CreatePackageService
def execute
find_or_create_package!(::Packages::Package.package_types['generic']) do |package|
if params[:build].present?
package.build_infos.new(pipeline: params[:build].pipeline)
end
end
find_or_create_package!(::Packages::Package.package_types['generic'])
end
end
end
......
......@@ -46,7 +46,7 @@ module Packages
.execute
end
package.build_infos.create!(pipeline: params[:build].pipeline) if params[:build].present?
package.build_infos.safe_find_or_create_by!(pipeline: params[:build].pipeline) if params[:build].present?
package
end
......
......@@ -17,10 +17,6 @@ module Packages
def create_npm_package!
package = create_package!(:npm, name: name, version: version)
if build.present?
package.build_infos.create!(pipeline: build.pipeline)
end
::Packages::CreatePackageFileService.new(package, file_params).execute
::Packages::CreateDependencyService.new(package, package_dependencies).execute
::Packages::Npm::CreateTagService.new(package, dist_tag).execute
......@@ -50,10 +46,6 @@ module Packages
params[:versions][version]
end
def build
params[:build]
end
def dist_tag
params['dist-tags'].each_key.first
end
......
......@@ -19,6 +19,8 @@ module Packages
Packages::Pypi::Metadatum.upsert(meta.attributes)
::Packages::CreatePackageFileService.new(created_package, file_params).execute
created_package
end
end
......@@ -32,6 +34,7 @@ module Packages
def file_params
{
build: params[:build],
file: params[:content],
file_name: params[:content].original_filename,
file_md5: params[:md5_digest],
......
---
title: Create package build_info records for Conan, NuGet, PyPI, and Composer packages
and package files
merge_request: 48811
author:
type: added
---
title: Fix bug in ProjectRepositoryStorageMove transition to scheduled
merge_request: 49105
author:
type: fixed
......@@ -498,6 +498,7 @@ To configure Praefect with TLS:
**For Omnibus GitLab**
1. Create certificates for Praefect servers.
1. On the Praefect servers, create the `/etc/gitlab/ssl` directory and copy your key
and certificate there:
......@@ -516,7 +517,8 @@ To configure Praefect with TLS:
praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. On the Praefect clients (including each Gitaly server), copy the certificates,
or their certificate authority, into `/etc/gitlab/trusted-certs`:
......@@ -529,8 +531,10 @@ To configure Praefect with TLS:
```ruby
git_data_dirs({
'default' => { 'gitaly_address' => 'tls://praefect1.internal:3305' },
'storage1' => { 'gitaly_address' => 'tls://praefect2.internal:3305' },
"default" => {
"gitaly_address" => 'tls://LOAD_BALANCER_SERVER_ADDRESS:2305',
"gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
}
})
```
......@@ -565,10 +569,7 @@ To configure Praefect with TLS:
repositories:
storages:
default:
gitaly_address: tls://praefect1.internal:3305
path: /some/local/path
storage1:
gitaly_address: tls://praefect2.internal:3305
gitaly_address: tls://LOAD_BALANCER_SERVER_ADDRESS:3305
path: /some/local/path
```
......@@ -834,6 +835,8 @@ Particular attention should be shown to:
balancer.
- `PRAEFECT_EXTERNAL_TOKEN` with the real secret
If you are using TLS, the `gitaly_address` should begin with `tls://`.
```ruby
git_data_dirs({
"default" => {
......
......@@ -104,37 +104,6 @@ describe('Component', () => {
Remember that the performance of each test depends on the environment.
### Timout error due to async components
If your component is fetching some other components asynchroneously based on some conditions, it might happen so that your Jest suite for this component will become flaky timing out from time to time.
```javascript
// ide.vue
export default {
components: {
'error-message': () => import('./error_message.vue'),
'gl-button': () => import('@gitlab/ui/src/components/base/button/button.vue'),
...
};
```
To address this issue, you can "help" Jest by stubbing the async components so that Jest would not need to fetch those asynchroneously at the run-time.
```javascript
// ide_spec.js
import { GlButton } from '@gitlab/ui';
import ErrorMessage from '~/ide/components/error_message.vue';
...
return shallowMount(ide, {
...
stubs: {
ErrorMessage,
GlButton,
...
},
})
```
## What and how to test
Before jumping into more gritty details about Jest-specific workflows like mocks and spies, we should briefly cover what to test with Jest.
......
......@@ -160,6 +160,9 @@ Configure the GitLab integration with Jenkins.
### Option 2: Webhook
If you are unable to provide GitLab with your Jenkins server login, you can use this option
to integrate GitLab and Jenkins.
1. In the configuration of your Jenkins job, in the GitLab configuration section, click **Advanced**.
1. Click the **Generate** button under the **Secret Token** field.
1. Copy the resulting token, and save the job configuration.
......
......@@ -132,7 +132,7 @@ module API
track_package_event('push_package', :composer)
::Packages::Composer::CreatePackageService
.new(authorized_user_project, current_user, declared_params)
.new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
.execute
created!
......
......@@ -164,7 +164,11 @@ module API
end
def find_or_create_package
package || ::Packages::Conan::CreatePackageService.new(project, current_user, params).execute
package || ::Packages::Conan::CreatePackageService.new(
project,
current_user,
params.merge(build: current_authenticated_job)
).execute
end
def track_push_package_event
......@@ -184,7 +188,11 @@ module API
def create_package_file_with_type(file_type, current_package)
unless params[:file].size == 0 # rubocop: disable Style/ZeroLengthPredicate
# conan sends two upload requests, the first has no file, so we skip record creation if file.size == 0
::Packages::Conan::CreatePackageFileService.new(current_package, params[:file], params.merge(conan_file_type: file_type)).execute
::Packages::Conan::CreatePackageFileService.new(
current_package,
params[:file],
params.merge(conan_file_type: file_type, build: current_authenticated_job)
).execute
end
end
......
......@@ -101,11 +101,16 @@ module API
file_name: PACKAGE_FILENAME
)
package = ::Packages::Nuget::CreatePackageService.new(authorized_user_project, current_user)
.execute
package_file = ::Packages::CreatePackageFileService.new(package, file_params)
.execute
package = ::Packages::Nuget::CreatePackageService.new(
authorized_user_project,
current_user,
declared_params.merge(build: current_authenticated_job)
).execute
package_file = ::Packages::CreatePackageFileService.new(
package,
file_params.merge(build: current_authenticated_job)
).execute
track_package_event('push_package', :nuget)
......
......@@ -127,7 +127,7 @@ module API
track_package_event('push_package', :pypi)
::Packages::Pypi::CreatePackageService
.new(authorized_user_project, current_user, declared_params)
.new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
.execute
created!
......
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import { createStore } from '~/ide/stores';
import ErrorMessage from '~/ide/components/error_message.vue';
import FindFile from '~/vue_shared/components/file_finder/index.vue';
import CommitEditorHeader from '~/ide/components/commit_sidebar/editor_header.vue';
import RepoTabs from '~/ide/components/repo_tabs.vue';
import IdeStatusBar from '~/ide/components/ide_status_bar.vue';
import RightPane from '~/ide/components/panes/right.vue';
import NewModal from '~/ide/components/new_dropdown/modal.vue';
import ide from '~/ide/components/ide.vue';
import { file } from '../helpers';
import { projectData } from '../mock_data';
......@@ -39,17 +32,6 @@ describe('WebIDE', () => {
return shallowMount(ide, {
store,
localVue,
stubs: {
ErrorMessage,
GlButton,
GlLoadingIcon,
CommitEditorHeader,
RepoTabs,
IdeStatusBar,
FindFile,
RightPane,
NewModal,
},
});
}
......@@ -74,27 +56,24 @@ describe('WebIDE', () => {
describe('ide component, non-empty repo', () => {
describe('error message', () => {
it('does not show error message when it is not set', () => {
wrapper = createComponent({
state: {
errorMessage: null,
},
});
expect(wrapper.find(ErrorMessage).exists()).toBe(false);
});
it('shows error message when set', () => {
wrapper = createComponent({
state: {
errorMessage: {
text: 'error',
it.each`
errorMessage | exists
${null} | ${false}
${{ text: 'error' }} | ${true}
`(
'should error message exists=$exists when errorMessage=$errorMessage',
async ({ errorMessage, exists }) => {
wrapper = createComponent({
state: {
errorMessage,
},
},
});
});
expect(wrapper.find(ErrorMessage).exists()).toBe(true);
});
await waitForPromises();
expect(wrapper.find(ErrorMessage).exists()).toBe(exists);
},
);
});
describe('onBeforeUnload', () => {
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { TEST_HOST } from 'spec/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import TerminalEmptyState from '~/ide/components/terminal/empty_state.vue';
import TerminalView from '~/ide/components/terminal/view.vue';
import TerminalSession from '~/ide/components/terminal/session.vue';
......@@ -17,7 +18,7 @@ describe('IDE TerminalView', () => {
let getters;
let wrapper;
const factory = () => {
const factory = async () => {
const store = new Vuex.Store({
modules: {
terminal: {
......@@ -30,6 +31,9 @@ describe('IDE TerminalView', () => {
});
wrapper = shallowMount(TerminalView, { localVue, store });
// Uses deferred components, so wait for those to load...
await waitForPromises();
};
beforeEach(() => {
......@@ -59,8 +63,8 @@ describe('IDE TerminalView', () => {
wrapper.destroy();
});
it('renders empty state', () => {
factory();
it('renders empty state', async () => {
await factory();
expect(wrapper.find(TerminalEmptyState).props()).toEqual({
helpPath: TEST_HELP_PATH,
......@@ -69,8 +73,8 @@ describe('IDE TerminalView', () => {
});
});
it('hides splash and starts, when started', () => {
factory();
it('hides splash and starts, when started', async () => {
await factory();
expect(actions.startSession).not.toHaveBeenCalled();
expect(actions.hideSplash).not.toHaveBeenCalled();
......@@ -81,9 +85,9 @@ describe('IDE TerminalView', () => {
expect(actions.hideSplash).toHaveBeenCalled();
});
it('shows Web Terminal when started', () => {
it('shows Web Terminal when started', async () => {
state.isShowSplash = false;
factory();
await factory();
expect(wrapper.find(TerminalEmptyState).exists()).toBe(false);
expect(wrapper.find(TerminalSession).exists()).toBe(true);
......
......@@ -73,6 +73,17 @@ RSpec.describe ProjectRepositoryStorageMove, type: :model do
expect(project).to be_repository_read_only
end
context 'when the transition fails' do
it 'does not trigger ProjectUpdateRepositoryStorageWorker and adds an error' do
allow(storage_move.project).to receive(:set_repository_read_only!).and_raise(StandardError, 'foobar')
expect(ProjectUpdateRepositoryStorageWorker).not_to receive(:perform_async)
storage_move.schedule!
expect(storage_move.errors[:project]).to include('foobar')
end
end
end
context 'and transits to started' do
......
......@@ -41,6 +41,8 @@ RSpec.describe Packages::Composer::CreatePackageService do
it_behaves_like 'assigns the package creator' do
let(:package) { created_package }
end
it_behaves_like 'assigns build to package'
end
context 'with a tag' do
......@@ -62,6 +64,8 @@ RSpec.describe Packages::Composer::CreatePackageService do
it_behaves_like 'assigns the package creator' do
let(:package) { created_package }
end
it_behaves_like 'assigns build to package'
end
end
......
......@@ -5,11 +5,12 @@ RSpec.describe Packages::Conan::CreatePackageFileService do
include WorkhorseHelpers
let_it_be(:package) { create(:conan_package) }
let_it_be(:user) { create(:user) }
describe '#execute' do
let(:file_name) { 'foo.tgz' }
subject { described_class.new(package, file, params) }
subject { described_class.new(package, file, params).execute }
shared_examples 'a valid package_file' do
let(:params) do
......@@ -27,7 +28,7 @@ RSpec.describe Packages::Conan::CreatePackageFileService do
end
it 'creates a new package file' do
package_file = subject.execute
package_file = subject
expect(package_file).to be_valid
expect(package_file.file_name).to eq(file_name)
......@@ -40,6 +41,8 @@ RSpec.describe Packages::Conan::CreatePackageFileService do
expect(package_file.conan_file_metadatum.conan_file_type).to eq('package_file')
expect(package_file.file.read).to eq('content')
end
it_behaves_like 'assigns build to package file'
end
shared_examples 'a valid recipe_file' do
......@@ -56,7 +59,7 @@ RSpec.describe Packages::Conan::CreatePackageFileService do
end
it 'creates a new recipe file' do
package_file = subject.execute
package_file = subject
expect(package_file).to be_valid
expect(package_file.file_name).to eq(file_name)
......@@ -69,6 +72,8 @@ RSpec.describe Packages::Conan::CreatePackageFileService do
expect(package_file.conan_file_metadatum.conan_file_type).to eq('recipe_file')
expect(package_file.file.read).to eq('content')
end
it_behaves_like 'assigns build to package file'
end
context 'with temp file' do
......@@ -123,7 +128,7 @@ RSpec.describe Packages::Conan::CreatePackageFileService do
end
it 'raises an error' do
expect { subject.execute }.to raise_error(ActiveRecord::RecordInvalid)
expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
......
......@@ -30,6 +30,7 @@ RSpec.describe Packages::Conan::CreatePackageService do
end
it_behaves_like 'assigns the package creator'
it_behaves_like 'assigns build to package'
end
context 'invalid params' do
......
......@@ -4,10 +4,11 @@ require 'spec_helper'
RSpec.describe Packages::CreatePackageFileService do
let_it_be(:package) { create(:maven_package) }
let_it_be(:user) { create(:user) }
subject { described_class.new(package, params) }
let(:service) { described_class.new(package, params) }
describe '#execute' do
subject { service.execute }
context 'with valid params' do
let(:params) do
{
......@@ -17,11 +18,13 @@ RSpec.describe Packages::CreatePackageFileService do
end
it 'creates a new package file' do
package_file = subject.execute
package_file = subject
expect(package_file).to be_valid
expect(package_file.file_name).to eq('foo.jar')
end
it_behaves_like 'assigns build to package file'
end
context 'file is missing' do
......@@ -32,17 +35,7 @@ RSpec.describe Packages::CreatePackageFileService do
end
it 'raises an error' do
expect { subject.execute }.to raise_error(ActiveRecord::RecordInvalid)
end
end
context 'with a build' do
let_it_be(:pipeline) { create(:ci_pipeline, user: user) }
let(:build) { double('build', pipeline: pipeline) }
let(:params) { { file: Tempfile.new, file_name: 'foo.jar', build: build } }
it 'creates a build_info' do
expect { subject.execute }.to change { Packages::PackageFileBuildInfo.count }.by(1)
expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
......
......@@ -23,6 +23,8 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
}
end
subject { described_class.new(project, user, params).execute }
before do
FileUtils.touch(temp_file)
end
......@@ -41,9 +43,7 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
expect(::Packages::Generic::FindOrCreatePackageService).to receive(:new).with(project, user, package_params).and_return(package_service)
expect(package_service).to receive(:execute).and_return(package)
service = described_class.new(project, user, params)
expect { service.execute }.to change { package.package_files.count }.by(1)
expect { subject }.to change { package.package_files.count }.by(1)
.and change { Packages::PackageFileBuildInfo.count }.by(1)
package_file = package.package_files.last
......@@ -54,5 +54,7 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
expect(package_file.file_sha256).to eq(sha256)
end
end
it_behaves_like 'assigns build to package file'
end
end
......@@ -31,5 +31,6 @@ RSpec.describe Packages::Nuget::CreatePackageService do
end
it_behaves_like 'assigns the package creator'
it_behaves_like 'assigns build to package'
end
end
......@@ -51,6 +51,8 @@ RSpec.describe Packages::Pypi::CreatePackageService do
let(:package) { created_package }
end
it_behaves_like 'assigns build to package'
context 'with an existing package' do
before do
described_class.new(project, user, params).execute
......
......@@ -14,6 +14,24 @@ RSpec.shared_examples 'assigns build to package' do
end
end
RSpec.shared_examples 'assigns build to package file' do
context 'with build info' do
let(:job) { create(:ci_build, user: user) }
let(:params) { super().merge(build: job) }
it 'assigns the pipeline to the package' do
package_file = subject
expect(package_file.package_file_build_infos).to be_present
expect(package_file.pipelines.first).to eq job.pipeline
end
it 'creates a new PackageFileBuildInfo record' do
expect { subject }.to change { Packages::PackageFileBuildInfo.count }.by(1)
end
end
end
RSpec.shared_examples 'assigns the package creator' do
it 'assigns the package creator' do
subject
......
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