Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-10-20 15:12:43 +00:00
parent 3ce7340b2a
commit dd1388bcdb
26 changed files with 299 additions and 194 deletions

View File

@ -3,6 +3,7 @@ import { GlAlert, GlLoadingIcon, GlTabs } from '@gitlab/ui';
import { s__ } from '~/locale';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getParameterValues, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
import {
CREATE_TAB,
EDITOR_APP_STATUS_EMPTY,
@ -12,6 +13,8 @@ import {
EDITOR_APP_STATUS_VALID,
LINT_TAB,
MERGED_TAB,
TAB_QUERY_PARAM,
TABS_INDEX,
VISUALIZE_TAB,
} from '../constants';
import getAppStatus from '../graphql/queries/client/app_status.graphql';
@ -42,6 +45,9 @@ export default {
errorTexts: {
loadMergedYaml: s__('Pipelines|Could not load merged YAML content'),
},
query: {
TAB_QUERY_PARAM,
},
tabConstants: {
CREATE_TAB,
LINT_TAB,
@ -98,15 +104,38 @@ export default {
return this.appStatus === EDITOR_APP_STATUS_LOADING;
},
},
created() {
const [tabQueryParam] = getParameterValues(TAB_QUERY_PARAM);
if (tabQueryParam && TABS_INDEX[tabQueryParam]) {
this.setDefaultTab(tabQueryParam);
}
},
methods: {
setCurrentTab(tabName) {
this.$emit('set-current-tab', tabName);
},
setDefaultTab(tabName) {
// We associate tab name with the index so that we can use tab name
// in other part of the app and load the corresponding tab closer to the
// actual component using a hash that binds the name to the indexes.
// This also means that if we ever changed tab order, we would justs need to
// update `TABS_INDEX` hash instead of all the instances in the app
// where we used the individual indexes
const newUrl = setUrlParams({ [TAB_QUERY_PARAM]: TABS_INDEX[tabName] });
this.setCurrentTab(tabName);
updateHistory({ url: newUrl, title: document.title, replace: true });
},
},
};
</script>
<template>
<gl-tabs class="file-editor gl-mb-3">
<gl-tabs
class="file-editor gl-mb-3"
:query-param-name="$options.query.TAB_QUERY_PARAM"
sync-active-tab-with-query-params
>
<editor-tab
class="gl-mb-3"
:title="$options.i18n.tabEdit"

View File

@ -22,7 +22,14 @@ export const LINT_TAB = 'LINT_TAB';
export const MERGED_TAB = 'MERGED_TAB';
export const VISUALIZE_TAB = 'VISUALIZE_TAB';
export const TABS_INDEX = {
[CREATE_TAB]: '0',
[VISUALIZE_TAB]: '1',
[LINT_TAB]: '2',
[MERGED_TAB]: '3',
};
export const TABS_WITH_COMMIT_FORM = [CREATE_TAB, LINT_TAB, VISUALIZE_TAB];
export const TAB_QUERY_PARAM = 'tab';
export const COMMIT_ACTION_CREATE = 'CREATE';
export const COMMIT_ACTION_UPDATE = 'UPDATE';

View File

@ -4,7 +4,7 @@ import PipelineEditorDrawer from './components/drawer/pipeline_editor_drawer.vue
import PipelineEditorFileNav from './components/file_nav/pipeline_editor_file_nav.vue';
import PipelineEditorHeader from './components/header/pipeline_editor_header.vue';
import PipelineEditorTabs from './components/pipeline_editor_tabs.vue';
import { TABS_WITH_COMMIT_FORM, CREATE_TAB } from './constants';
import { CREATE_TAB, TABS_WITH_COMMIT_FORM } from './constants';
export default {
components: {

View File

@ -14,10 +14,6 @@ export const parseGetProjectStorageResults = (data, helpLinks) => {
}
const { storageSize, ...storageStatistics } = projectStatistics;
const storageTypes = PROJECT_STORAGE_TYPES.reduce((types, currentType) => {
if (!storageStatistics[currentType.id]) {
return types;
}
const helpPathKey = currentType.id.replace(`Size`, `HelpPagePath`);
const helpPath = helpLinks[helpPathKey];

View File

@ -52,7 +52,7 @@ class Namespace < ApplicationRecord
belongs_to :owner, class_name: "User"
belongs_to :parent, class_name: "Namespace"
has_many :children, class_name: "Namespace", foreign_key: :parent_id
has_many :children, -> { where(type: Group.sti_name) }, class_name: "Namespace", foreign_key: :parent_id
has_many :custom_emoji, inverse_of: :namespace
has_one :chat_team, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :root_storage_statistics, class_name: 'Namespace::RootStorageStatistics'
@ -566,7 +566,7 @@ class Namespace < ApplicationRecord
end
if user_namespace?
errors.add(:parent_id, _('cannot not be used for user namespace'))
errors.add(:parent_id, _('cannot be used for user namespace'))
elsif group_namespace?
errors.add(:parent_id, _('user namespace cannot be the parent of another namespace')) if parent.user_namespace?
end

View File

@ -109,10 +109,6 @@ module Ci
end
def parse_artifact(artifact)
unless Feature.enabled?(:ci_synchronous_artifact_parsing, project, default_enabled: true)
return success
end
case artifact.file_type
when 'dotenv' then parse_dotenv_artifact(artifact)
else success

View File

@ -22,8 +22,8 @@
%ul
- @pipeline.yaml_errors.split(",").each do |error|
%li= error
- lint_link_url = project_ci_lint_path(@project)
- lint_link_start = '<a href="%{url}">'.html_safe % { url: lint_link_url }
- lint_link_url = project_ci_pipeline_editor_path(@project, tab: "LINT_TAB")
- lint_link_start = '<a href="%{url}" class="gl-text-blue-500!">'.html_safe % { url: lint_link_url }
= s_('You can also test your %{gitlab_ci_yml} in %{lint_link_start}CI Lint%{lint_link_end}').html_safe % { gitlab_ci_yml: '.gitlab-ci.yml', lint_link_start: lint_link_start, lint_link_end: '</a>'.html_safe }
= render "projects/pipelines/with_tabs", pipeline: @pipeline, stages: @stages, pipeline_has_errors: pipeline_has_errors

View File

@ -1,8 +0,0 @@
---
name: ci_synchronous_artifact_parsing
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26247
rollout_issue_url:
milestone: '12.9'
type: development
group: group::release
default_enabled: true

View File

@ -6,34 +6,39 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab.com for Jira Cloud app **(FREE)**
You can integrate GitLab and Jira Cloud using the
[GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud)
app in the Atlassian Marketplace.
NOTE:
Only Jira users with administrator level access are able to install or configure
Only Jira users with the administrator role can install or configure
the GitLab.com for Jira Cloud app.
## GitLab.com for Jira Cloud app **(FREE SAAS)**
## Install the GitLab.com for Jira Cloud app **(FREE SAAS)**
You can integrate GitLab.com and Jira Cloud using the
[GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud)
app in the Atlassian Marketplace. The user configuring GitLab.com for Jira Cloud app must have
[Maintainer](../../user/permissions.md) permissions in the GitLab.com namespace.
If you use GitLab.com and Jira Cloud, you can install the GitLab.com for Jira Cloud app.
If you do not use both of these environments, use the [Jira DVCS Connector](dvcs.md) or
[install GitLab.com for Jira Cloud app for self-managed instances](#install-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances).
We recommend the GitLab.com for Jira Cloud app, because data is
synchronized in real time. The DVCS connector updates data only once per hour.
This integration method supports [smart commits](dvcs.md#smart-commits).
The user configuring the GitLab.com for Jira Cloud app must have
at least the [Maintainer](../../user/permissions.md) role the GitLab.com namespace.
This method is recommended when using GitLab.com and Jira Cloud because data is
synchronized in real-time. The DVCS connector updates data only once per hour.
If you are not using both of these environments, use the [Jira DVCS Connector](dvcs.md) method or
[steps to install GitLab.com for Jira Cloud app for self-managed instances](#install-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances).
This integration method supports [Smart Commits](dvcs.md#smart-commits).
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For a walkthrough of the integration with GitLab.com for Jira Cloud app, watch
[Configure GitLab.com Jira Could Integration using Marketplace App](https://youtu.be/SwR-g1s1zTo) on YouTube.
1. Go to **Jira Settings > Apps > Find new apps**, then search for GitLab.
1. Click **GitLab.com for Jira Cloud**, then click **Get it now**, or go to the
To install the GitLab.com for Jira Cloud app:
1. In Jira, go to **Jira Settings > Apps > Find new apps**, then search for GitLab.
1. Select **GitLab.com for Jira Cloud**, then select **Get it now**, or go to the
[App in the marketplace directly](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud).
![Install GitLab.com app on Jira Cloud](img/jira_dev_panel_setup_com_1.png)
1. After installing, click **Get started** to go to the configurations page.
1. After installing, to go to the configurations page, select **Get started**.
This page is always available under **Jira Settings > Apps > Manage apps**.
![Start GitLab.com app configuration on Jira Cloud](img/jira_dev_panel_setup_com_2.png)
@ -41,7 +46,7 @@ For a walkthrough of the integration with GitLab.com for Jira Cloud app, watch
[Maintainer](../../user/permissions.md) permissions to add namespaces.
![Sign in to GitLab.com in GitLab.com for Jira Cloud app](img/jira_dev_panel_setup_com_3_v13_9.png)
1. Select **Add namespace** to open the list of available namespaces.
1. To open the list of available namespaces, select **Add namespace**.
1. Identify the namespace you want to link, and select **Link**. Only Jira site
administrators are permitted to add or remove namespaces for an installation.
@ -89,30 +94,30 @@ from outside the Marketplace, which allows you to install the application:
1. Sign in to your Jira instance as a user with an Administrator role.
1. Place your Jira instance into
[development mode](https://developer.atlassian.com/cloud/jira/platform/getting-started-with-connect/#step-2--enable-development-mode).
1. Sign in to your GitLab application as a user with an [Administrator](../../user/permissions.md) role.
1. Sign in to your GitLab application as an [administrator](../../user/permissions.md).
1. Install the GitLab application from your self-managed GitLab instance, as
described in the [Atlassian developer guides](https://developer.atlassian.com/cloud/jira/platform/getting-started-with-connect/#step-3--install-and-test-your-app):
1. In your Jira instance, go to **Apps > Manage Apps** and click **Upload app**:
1. In your Jira instance, go to **Apps > Manage Apps** and select **Upload app**:
![Image showing button labeled "upload app"](img/jira-upload-app_v13_11.png)
![Button labeled "upload app"](img/jira-upload-app_v13_11.png)
1. For **App descriptor URL**, provide full URL to your manifest file, modifying this
URL based on your instance configuration: `https://your.domain/your-path/-/jira_connect/app_descriptor.json`
1. Click **Upload**, and Jira fetches the content of your `app_descriptor` file and installs
it for you.
1. For **App descriptor URL**, provide the full URL to your manifest file, based
on your instance configuration. For example: `https://your.domain/your-path/-/jira_connect/app_descriptor.json`.
1. Select **Upload**. Jira fetches the content of your `app_descriptor` file and installs
it.
1. If the upload is successful, Jira displays a modal panel: **Installed and ready to go!**
Click **Get started** to configure the integration.
To configure the integration, select **Get started**.
![Image showing success modal](img/jira-upload-app-success_v13_11.png)
![Success modal](img/jira-upload-app-success_v13_11.png)
1. Disable [development mode](https://developer.atlassian.com/cloud/jira/platform/getting-started-with-connect/#step-2--enable-development-mode) on your Jira instance.
The **GitLab.com for Jira Cloud** app now displays under **Manage apps**. You can also
click **Get started** to open the configuration page rendered from your GitLab instance.
select **Get started** to open the configuration page rendered from your GitLab instance.
NOTE:
If a GitLab update makes changes to the application descriptor, you must uninstall, then reinstall, the
application.
If a GitLab update makes changes to the application descriptor, you must uninstall,
then reinstall the application.
### Create a Marketplace listing
@ -120,31 +125,33 @@ If you prefer to not use development mode on your Jira instance, you can create
your own Marketplace listing for your instance. This enables your application
to be installed from the Atlassian Marketplace.
For full instructions, review the Atlassian [guide to creating a marketplace listing](https://developer.atlassian.com/platform/marketplace/installing-cloud-apps/#creating-the-marketplace-listing). To create a
Marketplace listing, you must:
For full instructions, review the Atlassian [guide to creating a marketplace listing](https://developer.atlassian.com/platform/marketplace/installing-cloud-apps/#creating-the-marketplace-listing).
To create a Marketplace listing:
1. Register as a Marketplace vendor.
1. List your application, using the application descriptor URL.
1. List your application using the application descriptor URL.
- Your manifest file is located at: `https://your.domain/your-path/-/jira_connect/app_descriptor.json`
- GitLab recommends you list your application as `private`, because public
- We recommend you list your application as `private`, because public
applications can be viewed and installed by any user.
1. Generate test license tokens for your application.
Review the
[official Atlassian documentation](https://developer.atlassian.com/platform/marketplace/installing-cloud-apps/#creating-the-marketplace-listing)
for details.
NOTE:
Using this method, [updates are automated](#update-the-gitlabcom-for-jira-cloud-app)
the same way as when using our GitLab.com Marketplace listing.
This method uses [automated updates](#update-the-gitlabcom-for-jira-cloud-app)
the same way as our GitLab.com Marketplace listing.
## Troubleshoot GitLab.com for Jira Cloud app
The GitLab.com for Jira Cloud app uses an iframe to add namespaces on the
settings page. Some browsers block cross-site cookies, which can lead to a
message saying that the user needs to log in on GitLab.com even though the user
is already logged in.
### Browser displays sign-in message when already signed in
> "You need to sign in or sign up before continuing."
You might get the following message prompting you to sign in to GitLab.com
when you're already signed in:
In this case, use [Firefox](https://www.mozilla.org/en-US/firefox/), [Google Chrome](https://www.google.com/chrome/), or enable cross-site cookies in your browser.
```plaintext
You need to sign in or sign up before continuing.
```
GitLab.com for Jira Cloud app uses an iframe to add namespaces on the
settings page. Some browsers block cross-site cookies, which can lead to this issue.
To resolve this issue, use [Firefox](https://www.mozilla.org/en-US/firefox/),
[Google Chrome](https://www.google.com/chrome/), or enable cross-site cookies in your browser.

View File

@ -7,20 +7,17 @@ include:
- template: Terraform/Base.latest.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml
stages:
- init
- validate
- build
- deploy
- cleanup
init:
extends: .terraform:init
fmt:
extends: .terraform:fmt
needs: []
validate:
extends: .terraform:validate
needs: []
build:
extends: .terraform:build

View File

@ -21,18 +21,11 @@ cache:
paths:
- ${TF_ROOT}/.terraform/
.terraform:init: &terraform_init
stage: init
script:
- cd ${TF_ROOT}
- gitlab-terraform init
.terraform:fmt: &terraform_fmt
stage: validate
needs: []
script:
- cd ${TF_ROOT}
- gitlab-terraform fmt -check -recursive
- gitlab-terraform fmt
allow_failure: true
.terraform:validate: &terraform_validate

View File

@ -200,33 +200,6 @@ module Gitlab
row['result'] if row
end
# @param [ActiveRecord::Connection] ar_connection
# @return [String]
def get_write_location(ar_connection)
use_new_load_balancer_query = Gitlab::Utils
.to_boolean(ENV['USE_NEW_LOAD_BALANCER_QUERY'], default: true)
sql =
if use_new_load_balancer_query
<<~NEWSQL
SELECT CASE
WHEN pg_is_in_recovery() = true AND EXISTS (SELECT 1 FROM pg_stat_get_wal_senders())
THEN pg_last_wal_replay_lsn()::text
WHEN pg_is_in_recovery() = false
THEN pg_current_wal_insert_lsn()::text
ELSE NULL
END AS location;
NEWSQL
else
<<~SQL
SELECT pg_current_wal_insert_lsn()::text AS location
SQL
end
row = ar_connection.select_all(sql).first
row['location'] if row
end
# inside_transaction? will return true if the caller is running within a
# transaction. Handles special cases when running inside a test
# environment, where tests may be wrapped in transactions

View File

@ -133,7 +133,7 @@ module Gitlab
# Returns the transaction write location of the primary.
def primary_write_location
location = read_write do |connection|
::Gitlab::Database.main.get_write_location(connection)
get_write_location(connection)
end
return location if location
@ -268,6 +268,33 @@ module Gitlab
base = SafeRequestStore[:gitlab_load_balancer] ||= {}
base[self] ||= {}
end
# @param [ActiveRecord::Connection] ar_connection
# @return [String]
def get_write_location(ar_connection)
use_new_load_balancer_query = Gitlab::Utils
.to_boolean(ENV['USE_NEW_LOAD_BALANCER_QUERY'], default: true)
sql =
if use_new_load_balancer_query
<<~NEWSQL
SELECT CASE
WHEN pg_is_in_recovery() = true AND EXISTS (SELECT 1 FROM pg_stat_get_wal_senders())
THEN pg_last_wal_replay_lsn()::text
WHEN pg_is_in_recovery() = false
THEN pg_current_wal_insert_lsn()::text
ELSE NULL
END AS location;
NEWSQL
else
<<~SQL
SELECT pg_current_wal_insert_lsn()::text AS location
SQL
end
row = ar_connection.select_all(sql).first
row['location'] if row
end
end
end
end

View File

@ -39886,6 +39886,9 @@ msgstr ""
msgid "cannot be modified"
msgstr ""
msgid "cannot be used for user namespace"
msgstr ""
msgid "cannot block others"
msgstr ""
@ -39901,9 +39904,6 @@ msgstr ""
msgid "cannot merge"
msgstr ""
msgid "cannot not be used for user namespace"
msgstr ""
msgid "ciReport|%{degradedNum} degraded"
msgstr ""

View File

@ -10,7 +10,12 @@ function deploy_exists() {
helm status --namespace "${namespace}" "${release}" >/dev/null 2>&1
deploy_exists=$?
echoinfo "Deployment status for ${release} is ${deploy_exists}"
if [ $deploy_exists -eq 0 ]; then
echoinfo "Previous deployment for ${release} found."
else
echoerr "Previous deployment for ${release} NOT found."
fi
return $deploy_exists
}

View File

@ -65,5 +65,31 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
expect_graphql_errors_to_be_empty
end
end
context 'project storage count query' do
before do
project.statistics.update!(
repository_size: 3900000,
lfs_objects_size: 4800000,
build_artifacts_size: 400000,
pipeline_artifacts_size: 400000,
wiki_size: 300000,
packages_size: 3800000,
uploads_size: 900000
)
end
base_input_path = 'projects/storage_counter/queries/'
base_output_path = 'graphql/projects/storage_counter/'
query_name = 'project_storage.query.graphql'
it "#{base_output_path}#{query_name}.json" do
query = get_graphql_query_as_string("#{base_input_path}#{query_name}")
post_graphql(query, current_user: user, variables: { fullPath: project.full_path })
expect_graphql_errors_to_be_empty
end
end
end
end

View File

@ -1,16 +1,21 @@
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import { GlAlert, GlLoadingIcon, GlTabs } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import setWindowLocation from 'helpers/set_window_location_helper';
import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue';
import CiLint from '~/pipeline_editor/components/lint/ci_lint.vue';
import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue';
import {
CREATE_TAB,
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_ERROR,
EDITOR_APP_STATUS_LOADING,
EDITOR_APP_STATUS_INVALID,
EDITOR_APP_STATUS_VALID,
MERGED_TAB,
TAB_QUERY_PARAM,
TABS_INDEX,
} from '~/pipeline_editor/constants';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import { mockLintResponse, mockCiYml } from '../mock_data';
@ -53,6 +58,7 @@ describe('Pipeline editor tabs component', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findCiLint = () => wrapper.findComponent(CiLint);
const findGlTabs = () => wrapper.findComponent(GlTabs);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findPipelineGraph = () => wrapper.findComponent(PipelineGraph);
const findTextEditor = () => wrapper.findComponent(MockTextEditor);
@ -181,4 +187,54 @@ describe('Pipeline editor tabs component', () => {
},
);
});
describe('default tab based on url query param', () => {
const gitlabUrl = 'https://gitlab.test/ci/editor/';
const matchObject = {
hostname: 'gitlab.test',
pathname: '/ci/editor/',
search: '',
};
it(`is ${CREATE_TAB} if the query param ${TAB_QUERY_PARAM} is not present`, () => {
setWindowLocation(gitlabUrl);
createComponent();
expect(window.location).toMatchObject(matchObject);
});
it(`is ${CREATE_TAB} tab if the query param ${TAB_QUERY_PARAM} is invalid`, () => {
const queryValue = 'FOO';
setWindowLocation(`${gitlabUrl}?${TAB_QUERY_PARAM}=${queryValue}`);
createComponent();
// If the query param remains unchanged, then we have ignored it.
expect(window.location).toMatchObject({
...matchObject,
search: `?${TAB_QUERY_PARAM}=${queryValue}`,
});
});
it('is the tab specified in query param and transform it into an index value', async () => {
setWindowLocation(`${gitlabUrl}?${TAB_QUERY_PARAM}=${MERGED_TAB}`);
createComponent();
// If the query param has changed to an index, it means we have synced the
// query with.
expect(window.location).toMatchObject({
...matchObject,
search: `?${TAB_QUERY_PARAM}=${TABS_INDEX[MERGED_TAB]}`,
});
});
});
describe('glTabs', () => {
beforeEach(() => {
createComponent();
});
it('passes the `sync-active-tab-with-query-params` prop', () => {
expect(findGlTabs().props('syncActiveTabWithQueryParams')).toBe(true);
});
});
});

View File

@ -1,11 +1,9 @@
import { GlAlert, GlButton, GlLoadingIcon, GlTabs } from '@gitlab/ui';
import { GlAlert, GlButton, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue';
import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
@ -35,10 +33,6 @@ import {
const localVue = createLocalVue();
localVue.use(VueApollo);
const MockSourceEditor = {
template: '<div/>',
};
const mockProvide = {
ciConfigPath: mockCiConfigPath,
defaultBranch: mockDefaultBranch,
@ -55,19 +49,15 @@ describe('Pipeline editor app component', () => {
let mockLatestCommitShaQuery;
let mockPipelineQuery;
const createComponent = ({ blobLoading = false, options = {}, provide = {} } = {}) => {
const createComponent = ({
blobLoading = false,
options = {},
provide = {},
stubs = {},
} = {}) => {
wrapper = shallowMount(PipelineEditorApp, {
provide: { ...mockProvide, ...provide },
stubs: {
GlTabs,
GlButton,
CommitForm,
PipelineEditorHome,
PipelineEditorTabs,
PipelineEditorMessages,
SourceEditor: MockSourceEditor,
PipelineEditorEmptyState,
},
stubs,
data() {
return {
commitSha: '',
@ -89,7 +79,7 @@ describe('Pipeline editor app component', () => {
});
};
const createComponentWithApollo = async ({ props = {}, provide = {} } = {}) => {
const createComponentWithApollo = async ({ props = {}, provide = {}, stubs = {} } = {}) => {
const handlers = [
[getBlobContent, mockBlobContentData],
[getCiConfigData, mockCiConfigData],
@ -111,7 +101,7 @@ describe('Pipeline editor app component', () => {
apolloProvider: mockApollo,
};
createComponent({ props, provide, options });
createComponent({ props, provide, stubs, options });
return waitForPromises();
};
@ -119,7 +109,6 @@ describe('Pipeline editor app component', () => {
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findAlert = () => wrapper.findComponent(GlAlert);
const findEditorHome = () => wrapper.findComponent(PipelineEditorHome);
const findTextEditor = () => wrapper.findComponent(TextEditor);
const findEmptyState = () => wrapper.findComponent(PipelineEditorEmptyState);
const findEmptyStateButton = () =>
wrapper.findComponent(PipelineEditorEmptyState).findComponent(GlButton);
@ -141,7 +130,7 @@ describe('Pipeline editor app component', () => {
createComponent({ blobLoading: true });
expect(findLoadingIcon().exists()).toBe(true);
expect(findTextEditor().exists()).toBe(false);
expect(findEditorHome().exists()).toBe(false);
});
});
@ -185,7 +174,11 @@ describe('Pipeline editor app component', () => {
describe('when no CI config file exists', () => {
beforeEach(async () => {
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
await createComponentWithApollo();
await createComponentWithApollo({
stubs: {
PipelineEditorEmptyState,
},
});
jest
.spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling')
@ -207,7 +200,11 @@ describe('Pipeline editor app component', () => {
const loadUnknownFailureText = 'The CI configuration was not loaded, please try again.';
mockBlobContentData.mockRejectedValueOnce(new Error('My error!'));
await createComponentWithApollo();
await createComponentWithApollo({
stubs: {
PipelineEditorMessages,
},
});
expect(findEmptyState().exists()).toBe(false);
@ -222,15 +219,20 @@ describe('Pipeline editor app component', () => {
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
mockLatestCommitShaQuery.mockResolvedValue(mockEmptyCommitShaResults);
await createComponentWithApollo();
await createComponentWithApollo({
stubs: {
PipelineEditorHome,
PipelineEditorEmptyState,
},
});
expect(findEmptyState().exists()).toBe(true);
expect(findTextEditor().exists()).toBe(false);
expect(findEditorHome().exists()).toBe(false);
await findEmptyStateButton().vm.$emit('click');
expect(findEmptyState().exists()).toBe(false);
expect(findTextEditor().exists()).toBe(true);
expect(findEditorHome().exists()).toBe(true);
});
});
@ -241,7 +243,7 @@ describe('Pipeline editor app component', () => {
describe('and the commit mutation succeeds', () => {
beforeEach(async () => {
window.scrollTo = jest.fn();
await createComponentWithApollo();
await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
findEditorHome().vm.$emit('commit', { type: COMMIT_SUCCESS });
});
@ -295,7 +297,7 @@ describe('Pipeline editor app component', () => {
beforeEach(async () => {
window.scrollTo = jest.fn();
await createComponentWithApollo();
await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
findEditorHome().vm.$emit('showError', {
type: COMMIT_FAILURE,
@ -319,7 +321,7 @@ describe('Pipeline editor app component', () => {
beforeEach(async () => {
window.scrollTo = jest.fn();
await createComponentWithApollo();
await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
findEditorHome().vm.$emit('showError', {
type: COMMIT_FAILURE,
@ -386,7 +388,9 @@ describe('Pipeline editor app component', () => {
});
it('renders the given template', async () => {
await createComponentWithApollo();
await createComponentWithApollo({
stubs: { PipelineEditorHome, PipelineEditorTabs },
});
expect(mockGetTemplate).toHaveBeenCalledWith({
projectPath: mockProjectFullPath,
@ -394,7 +398,7 @@ describe('Pipeline editor app component', () => {
});
expect(findEmptyState().exists()).toBe(false);
expect(findTextEditor().exists()).toBe(true);
expect(findEditorHome().exists()).toBe(true);
});
});
});

View File

@ -39,7 +39,6 @@ describe('Pipeline editor home wrapper', () => {
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('renders', () => {

View File

@ -1,23 +1,6 @@
export const mockGetProjectStorageCountGraphQLResponse = {
data: {
project: {
id: 'gid://gitlab/Project/20',
statistics: {
buildArtifactsSize: 400000.0,
pipelineArtifactsSize: 25000.0,
lfsObjectsSize: 4800000.0,
packagesSize: 3800000.0,
repositorySize: 3900000.0,
snippetsSize: 1200000.0,
storageSize: 15300000.0,
uploadsSize: 900000.0,
wikiSize: 300000.0,
__typename: 'ProjectStatistics',
},
__typename: 'Project',
},
},
};
import mockGetProjectStorageCountGraphQLResponse from 'test_fixtures/graphql/projects/storage_counter/project_storage.query.graphql.json';
export { mockGetProjectStorageCountGraphQLResponse };
export const mockEmptyResponse = { data: { project: null } };
@ -37,7 +20,7 @@ export const defaultProvideValues = {
export const projectData = {
storage: {
totalUsage: '14.6 MiB',
totalUsage: '13.8 MiB',
storageTypes: [
{
storageType: {
@ -84,7 +67,7 @@ export const projectData = {
description: 'Shared bits of code and text.',
helpPath: '/snippets',
},
value: 1200000,
value: 0,
},
{
storageType: {

View File

@ -14,4 +14,21 @@ describe('parseGetProjectStorageResults', () => {
),
).toMatchObject(projectData);
});
it('includes storage type with size of 0 in returned value', () => {
const mockedResponse = mockGetProjectStorageCountGraphQLResponse.data;
// ensuring a specific storage type item has size of 0
mockedResponse.project.statistics.repositorySize = 0;
const response = parseGetProjectStorageResults(mockedResponse, defaultProvideValues.helpLinks);
expect(response.storage.storageTypes).toEqual(
expect.arrayContaining([
{
storageType: expect.any(Object),
value: 0,
},
]),
);
});
});

View File

@ -27,7 +27,7 @@ RSpec.describe 'Terraform.latest.gitlab-ci.yml' do
context 'on master branch' do
it 'creates init, validate and build jobs', :aggregate_failures do
expect(pipeline.errors).to be_empty
expect(build_names).to include('init', 'validate', 'build', 'deploy')
expect(build_names).to include('validate', 'build', 'deploy')
end
end

View File

@ -428,15 +428,4 @@ RSpec.describe Gitlab::Database::Connection do
expect(connection.system_id).to be_an_instance_of(Integer)
end
end
describe '#get_write_location' do
it 'returns a string' do
expect(connection.get_write_location(connection.scope.connection))
.to be_a(String)
end
it 'returns nil if there are no results' do
expect(connection.get_write_location(double(select_all: []))).to be_nil
end
end
end

View File

@ -441,4 +441,15 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
lb.disconnect!(timeout: 30)
end
end
describe '#get_write_location' do
it 'returns a string' do
expect(lb.send(:get_write_location, lb.pool.connection))
.to be_a(String)
end
it 'returns nil if there are no results' do
expect(lb.send(:get_write_location, double(select_all: []))).to be_nil
end
end
end

View File

@ -28,6 +28,16 @@ RSpec.describe Namespace do
it { is_expected.to have_one :onboarding_progress }
it { is_expected.to have_one :admin_note }
it { is_expected.to have_many :pending_builds }
describe '#children' do
let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:project_namespace) { create(:project_namespace, parent: group) }
it 'excludes project namespaces' do
expect(group.children).to match_array([subgroup])
end
end
end
describe 'validations' do
@ -50,10 +60,10 @@ RSpec.describe Namespace do
ref(:project_sti_name) | ref(:user_sti_name) | 'project namespace cannot be the parent of another namespace'
ref(:project_sti_name) | ref(:group_sti_name) | 'project namespace cannot be the parent of another namespace'
ref(:project_sti_name) | ref(:project_sti_name) | 'project namespace cannot be the parent of another namespace'
ref(:group_sti_name) | ref(:user_sti_name) | 'cannot not be used for user namespace'
ref(:group_sti_name) | ref(:user_sti_name) | 'cannot be used for user namespace'
ref(:group_sti_name) | ref(:group_sti_name) | nil
ref(:group_sti_name) | ref(:project_sti_name) | nil
ref(:user_sti_name) | ref(:user_sti_name) | 'cannot not be used for user namespace'
ref(:user_sti_name) | ref(:user_sti_name) | 'cannot be used for user namespace'
ref(:user_sti_name) | ref(:group_sti_name) | 'user namespace cannot be the parent of another namespace'
ref(:user_sti_name) | ref(:project_sti_name) | nil
end
@ -273,8 +283,8 @@ RSpec.describe Namespace do
describe '.by_parent' do
it 'includes correct namespaces' do
expect(described_class.by_parent(namespace1.id)).to eq([namespace1sub])
expect(described_class.by_parent(namespace2.id)).to eq([namespace2sub])
expect(described_class.by_parent(namespace1.id)).to match_array([namespace1sub])
expect(described_class.by_parent(namespace2.id)).to match_array([namespace2sub])
expect(described_class.by_parent(nil)).to match_array([namespace, namespace1, namespace2])
end
end

View File

@ -175,18 +175,6 @@ RSpec.describe Ci::JobArtifacts::CreateService do
hash_including('key' => 'KEY1', 'value' => 'VAR1', 'source' => 'dotenv'),
hash_including('key' => 'KEY2', 'value' => 'VAR2', 'source' => 'dotenv'))
end
context 'when ci_synchronous_artifact_parsing feature flag is disabled' do
before do
stub_feature_flags(ci_synchronous_artifact_parsing: false)
end
it 'does not call parse service' do
expect(Ci::ParseDotenvArtifactService).not_to receive(:new)
expect(subject[:status]).to eq(:success)
end
end
end
context 'when artifact_type is metrics' do