summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters.vue61
-rw-r--r--app/assets/javascripts/clusters_list/constants.js11
-rw-r--r--app/assets/javascripts/clusters_list/index.js22
-rw-r--r--app/assets/javascripts/clusters_list/store/actions.js18
-rw-r--r--app/assets/javascripts/clusters_list/store/index.js16
-rw-r--r--app/assets/javascripts/clusters_list/store/mutation_types.js2
-rw-r--r--app/assets/javascripts/clusters_list/store/mutations.js12
-rw-r--r--app/assets/javascripts/clusters_list/store/state.js19
-rw-r--r--app/assets/javascripts/pages/admin/clusters/index/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/clusters/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/clusters/index/index.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/serializers/merge_request_widget_entity.rb4
-rw-r--r--app/views/clusters/clusters/index.html.haml23
-rw-r--r--changelogs/unreleased/207181-status-page-settings-backend.yml5
-rw-r--r--db/migrate/20200224020219_add_status_page_settings.rb18
-rw-r--r--db/schema.rb13
-rw-r--r--locale/gitlab.pot16
-rw-r--r--spec/features/projects/clusters_spec.rb1
-rw-r--r--spec/frontend/clusters_list/components/clusters_spec.js55
-rw-r--r--spec/frontend/clusters_list/store/actions_spec.js50
-rw-r--r--spec/frontend/vue_mr_widget/mock_data.js1
-rw-r--r--spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js6
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/serializers/merge_request_widget_entity_spec.rb7
25 files changed, 356 insertions, 12 deletions
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue
new file mode 100644
index 00000000000..9322423370b
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/components/clusters.vue
@@ -0,0 +1,61 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import { GlTable, GlLoadingIcon, GlBadge } from '@gitlab/ui';
+import { CLUSTER_TYPES } from '../constants';
+import { __ } from '~/locale';
+
+export default {
+ components: {
+ GlTable,
+ GlLoadingIcon,
+ GlBadge,
+ },
+ fields: [
+ {
+ key: 'name',
+ label: __('Kubernetes cluster'),
+ },
+ {
+ key: 'environmentScope',
+ label: __('Environment scope'),
+ },
+ {
+ key: 'size',
+ label: __('Size'),
+ },
+ {
+ key: 'clusterType',
+ label: __('Cluster level'),
+ formatter: value => CLUSTER_TYPES[value],
+ },
+ ],
+ computed: {
+ ...mapState(['clusters', 'loading']),
+ },
+ mounted() {
+ // TODO - uncomment this once integrated with BE
+ // this.fetchClusters();
+ },
+ methods: {
+ ...mapActions(['fetchClusters']),
+ },
+};
+</script>
+
+<template>
+ <gl-loading-icon v-if="loading" size="md" class="mt-3" />
+ <gl-table
+ v-else
+ :items="clusters"
+ :fields="$options.fields"
+ stacked="md"
+ variant="light"
+ class="qa-clusters-table"
+ >
+ <template #cell(clusterType)="{value}">
+ <gl-badge variant="light">
+ {{ value }}
+ </gl-badge>
+ </template>
+ </gl-table>
+</template>
diff --git a/app/assets/javascripts/clusters_list/constants.js b/app/assets/javascripts/clusters_list/constants.js
new file mode 100644
index 00000000000..4125288b5a5
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/constants.js
@@ -0,0 +1,11 @@
+import { __ } from '~/locale';
+
+export const CLUSTER_TYPES = {
+ project_type: __('Project'),
+ group_type: __('Group'),
+ instance_type: __('Instance'),
+};
+
+export default {
+ CLUSTER_TYPES,
+};
diff --git a/app/assets/javascripts/clusters_list/index.js b/app/assets/javascripts/clusters_list/index.js
new file mode 100644
index 00000000000..67d0a33030b
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/index.js
@@ -0,0 +1,22 @@
+import Vue from 'vue';
+import Clusters from './components/clusters.vue';
+import { createStore } from './store';
+
+export default () => {
+ const entryPoint = document.querySelector('#js-clusters-list-app');
+
+ if (!entryPoint) {
+ return;
+ }
+
+ const { endpoint } = entryPoint.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: '#js-clusters-list-app',
+ store: createStore({ endpoint }),
+ render(createElement) {
+ return createElement(Clusters);
+ },
+ });
+};
diff --git a/app/assets/javascripts/clusters_list/store/actions.js b/app/assets/javascripts/clusters_list/store/actions.js
new file mode 100644
index 00000000000..39fd9fdf625
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/store/actions.js
@@ -0,0 +1,18 @@
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import axios from '~/lib/utils/axios_utils';
+import flash from '~/flash';
+import { __ } from '~/locale';
+import * as types from './mutation_types';
+
+export const fetchClusters = ({ state, commit }) => {
+ return axios
+ .get(state.endpoint)
+ .then(({ data }) => {
+ commit(types.SET_CLUSTERS_DATA, convertObjectPropsToCamelCase(data, { deep: true }));
+ commit(types.SET_LOADING_STATE, false);
+ })
+ .catch(() => flash(__('An error occurred while loading clusters')));
+};
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/clusters_list/store/index.js b/app/assets/javascripts/clusters_list/store/index.js
new file mode 100644
index 00000000000..c472d2f354c
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/store/index.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import state from './state';
+import mutations from './mutations';
+import * as actions from './actions';
+
+Vue.use(Vuex);
+
+export const createStore = initialState =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: state(initialState),
+ });
+
+export default createStore;
diff --git a/app/assets/javascripts/clusters_list/store/mutation_types.js b/app/assets/javascripts/clusters_list/store/mutation_types.js
new file mode 100644
index 00000000000..f056f3ab7d9
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/store/mutation_types.js
@@ -0,0 +1,2 @@
+export const SET_CLUSTERS_DATA = 'SET_CLUSTERS_DATA';
+export const SET_LOADING_STATE = 'SET_LOADING_STATE';
diff --git a/app/assets/javascripts/clusters_list/store/mutations.js b/app/assets/javascripts/clusters_list/store/mutations.js
new file mode 100644
index 00000000000..ffd3c4601bf
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/store/mutations.js
@@ -0,0 +1,12 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.SET_LOADING_STATE](state, value) {
+ state.loading = value;
+ },
+ [types.SET_CLUSTERS_DATA](state, clusters) {
+ Object.assign(state, {
+ clusters,
+ });
+ },
+};
diff --git a/app/assets/javascripts/clusters_list/store/state.js b/app/assets/javascripts/clusters_list/store/state.js
new file mode 100644
index 00000000000..e6cdf9d67db
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/store/state.js
@@ -0,0 +1,19 @@
+export default (initialState = {}) => ({
+ endpoint: initialState.endpoint,
+ loading: false, // TODO - set this to true once integrated with BE
+ clusters: [
+ // TODO - remove mock data once integrated with BE
+ // {
+ // name: 'My Cluster',
+ // environmentScope: '*',
+ // size: '3',
+ // clusterType: 'group_type',
+ // },
+ // {
+ // name: 'My other cluster',
+ // environmentScope: 'production',
+ // size: '12',
+ // clusterType: 'project_type',
+ // },
+ ],
+});
diff --git a/app/assets/javascripts/pages/admin/clusters/index/index.js b/app/assets/javascripts/pages/admin/clusters/index/index.js
index 30d519d0e37..744be65bfbe 100644
--- a/app/assets/javascripts/pages/admin/clusters/index/index.js
+++ b/app/assets/javascripts/pages/admin/clusters/index/index.js
@@ -1,6 +1,8 @@
import PersistentUserCallout from '~/persistent_user_callout';
+import initClustersListApp from '~/clusters_list';
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
PersistentUserCallout.factory(callout);
+ initClustersListApp();
});
diff --git a/app/assets/javascripts/pages/groups/clusters/index/index.js b/app/assets/javascripts/pages/groups/clusters/index/index.js
index 30d519d0e37..744be65bfbe 100644
--- a/app/assets/javascripts/pages/groups/clusters/index/index.js
+++ b/app/assets/javascripts/pages/groups/clusters/index/index.js
@@ -1,6 +1,8 @@
import PersistentUserCallout from '~/persistent_user_callout';
+import initClustersListApp from '~/clusters_list';
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
PersistentUserCallout.factory(callout);
+ initClustersListApp();
});
diff --git a/app/assets/javascripts/pages/projects/clusters/index/index.js b/app/assets/javascripts/pages/projects/clusters/index/index.js
index 30d519d0e37..744be65bfbe 100644
--- a/app/assets/javascripts/pages/projects/clusters/index/index.js
+++ b/app/assets/javascripts/pages/projects/clusters/index/index.js
@@ -1,6 +1,8 @@
import PersistentUserCallout from '~/persistent_user_callout';
+import initClustersListApp from '~/clusters_list';
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
PersistentUserCallout.factory(callout);
+ initClustersListApp();
});
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 91ac23f427d..2aecd0938e4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -180,6 +180,7 @@ export default class MergeRequestStore {
this.mergeRequestAddCiConfigPath = data.merge_request_add_ci_config_path;
this.pipelinesEmptySvgPath = data.pipelines_empty_svg_path;
this.humanAccess = data.human_access;
+ this.newPipelinePath = data.new_project_pipeline_path;
}
get isNothingToMergeState() {
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 6df26de529d..7ba15dd9acf 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -64,6 +64,10 @@ class MergeRequestWidgetEntity < Grape::Entity
merge_request.project.team.human_max_access(current_user&.id)
end
+ expose :new_project_pipeline_path do |merge_request|
+ new_project_pipeline_path(merge_request.project)
+ end
+
# Rendering and redacting Markdown can be expensive. These links are
# just nice to have in the merge request widget, so only
# include them if they are explicitly requested on first load.
diff --git a/app/views/clusters/clusters/index.html.haml b/app/views/clusters/clusters/index.html.haml
index 049010cadf4..28002dbff92 100644
--- a/app/views/clusters/clusters/index.html.haml
+++ b/app/views/clusters/clusters/index.html.haml
@@ -18,13 +18,16 @@
%strong
= link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
- .clusters-table.js-clusters-list
- .gl-responsive-table-row.table-row-header{ role: "row" }
- .table-section.section-60{ role: "rowheader" }
- = s_("ClusterIntegration|Kubernetes cluster")
- .table-section.section-30{ role: "rowheader" }
- = s_("ClusterIntegration|Environment scope")
- .table-section.section-10{ role: "rowheader" }
- - @clusters.each do |cluster|
- = render "cluster", cluster: cluster.present(current_user: current_user)
- = paginate @clusters, theme: "gitlab"
+ - if Feature.enabled?(:clusters_list_redesign)
+ #js-clusters-list-app{ data: { endpoint: 'todo/add/endpoint' } }
+ - else
+ .clusters-table.js-clusters-list
+ .gl-responsive-table-row.table-row-header{ role: "row" }
+ .table-section.section-60{ role: "rowheader" }
+ = s_("ClusterIntegration|Kubernetes cluster")
+ .table-section.section-30{ role: "rowheader" }
+ = s_("ClusterIntegration|Environment scope")
+ .table-section.section-10{ role: "rowheader" }
+ - @clusters.each do |cluster|
+ = render "cluster", cluster: cluster.present(current_user: current_user)
+ = paginate @clusters, theme: "gitlab"
diff --git a/changelogs/unreleased/207181-status-page-settings-backend.yml b/changelogs/unreleased/207181-status-page-settings-backend.yml
new file mode 100644
index 00000000000..69758009099
--- /dev/null
+++ b/changelogs/unreleased/207181-status-page-settings-backend.yml
@@ -0,0 +1,5 @@
+---
+title: Create table & setup operations endpoint for Status Page Settings
+merge_request: 25863
+author:
+type: added
diff --git a/db/migrate/20200224020219_add_status_page_settings.rb b/db/migrate/20200224020219_add_status_page_settings.rb
new file mode 100644
index 00000000000..b960b60881e
--- /dev/null
+++ b/db/migrate/20200224020219_add_status_page_settings.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddStatusPageSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ create_table :status_page_settings, id: false do |t|
+ t.references :project, index: true, primary_key: true, foreign_key: { on_delete: :cascade }, unique: true, null: false
+ t.timestamps_with_timezone null: false
+ t.boolean :enabled, default: false, null: false
+ t.string :aws_s3_bucket_name, limit: 63, null: false
+ t.string :aws_region, limit: 255, null: false
+ t.string :aws_access_key, limit: 255, null: false
+ t.string :encrypted_aws_secret_key, limit: 255, null: false
+ t.string :encrypted_aws_secret_key_iv, limit: 255, null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 188062b8897..cb632d983f9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -4002,6 +4002,18 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do
t.boolean "recaptcha_verified", default: false, null: false
end
+ create_table "status_page_settings", primary_key: "project_id", force: :cascade do |t|
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "enabled", default: false, null: false
+ t.string "aws_s3_bucket_name", limit: 63, null: false
+ t.string "aws_region", limit: 255, null: false
+ t.string "aws_access_key", limit: 255, null: false
+ t.string "encrypted_aws_secret_key", limit: 255, null: false
+ t.string "encrypted_aws_secret_key_iv", limit: 255, null: false
+ t.index ["project_id"], name: "index_status_page_settings_on_project_id"
+ end
+
create_table "subscriptions", id: :serial, force: :cascade do |t|
t.integer "user_id"
t.integer "subscribable_id"
@@ -5018,6 +5030,7 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do
add_foreign_key "snippets", "projects", name: "fk_be41fd4bb7", on_delete: :cascade
add_foreign_key "software_license_policies", "projects", on_delete: :cascade
add_foreign_key "software_license_policies", "software_licenses", on_delete: :cascade
+ add_foreign_key "status_page_settings", "projects", on_delete: :cascade
add_foreign_key "subscriptions", "projects", on_delete: :cascade
add_foreign_key "suggestions", "notes", on_delete: :cascade
add_foreign_key "system_note_metadata", "description_versions", name: "fk_fbd87415c9", on_delete: :nullify
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 08b7ec47129..d3b7fea73c9 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1862,6 +1862,9 @@ msgstr ""
msgid "An error occurred while loading chart data"
msgstr ""
+msgid "An error occurred while loading clusters"
+msgstr ""
+
msgid "An error occurred while loading commit signatures"
msgstr ""
@@ -3962,6 +3965,9 @@ msgstr ""
msgid "Cluster does not exist"
msgstr ""
+msgid "Cluster level"
+msgstr ""
+
msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}."
msgstr ""
@@ -7454,6 +7460,9 @@ msgstr ""
msgid "Environment does not have deployments"
msgstr ""
+msgid "Environment scope"
+msgstr ""
+
msgid "Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. Additionally, they can be masked so they are hidden in job logs, though they must match certain regexp requirements to do so. You can use environment variables for passwords, secret keys, or whatever you want."
msgstr ""
@@ -11181,6 +11190,9 @@ msgstr ""
msgid "Kubernetes Clusters"
msgstr ""
+msgid "Kubernetes cluster"
+msgstr ""
+
msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
msgstr ""
@@ -17192,10 +17204,10 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
-msgid "Security report is out of date. Please incorporate latest changes from %{targetBranchName}"
+msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
-msgid "Security report is out of date. Retry the pipeline for the target branch."
+msgid "Security report is out of date. Run %{newPipelineLinkStart}a new pipeline%{newPipelineLinkEnd} for the target branch (%{targetBranchName})"
msgstr ""
msgid "SecurityConfiguration|Configured"
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index ad51533c42c..fc2de4df5ec 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -11,6 +11,7 @@ describe 'Clusters', :js do
before do
project.add_maintainer(user)
gitlab_sign_in(user)
+ stub_feature_flags(clusters_list_redesign: false)
end
context 'when user does not have a cluster and visits cluster index page' do
diff --git a/spec/frontend/clusters_list/components/clusters_spec.js b/spec/frontend/clusters_list/components/clusters_spec.js
new file mode 100644
index 00000000000..825bc7813a5
--- /dev/null
+++ b/spec/frontend/clusters_list/components/clusters_spec.js
@@ -0,0 +1,55 @@
+import { createLocalVue, mount } from '@vue/test-utils';
+import { GlTable, GlLoadingIcon } from '@gitlab/ui';
+import Clusters from '~/clusters_list/components/clusters.vue';
+import Vuex from 'vuex';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Clusters', () => {
+ let wrapper;
+
+ const findTable = () => wrapper.find(GlTable);
+ const findLoader = () => wrapper.find(GlLoadingIcon);
+
+ const mountComponent = _state => {
+ const state = { clusters: [], endpoint: 'some/endpoint', ..._state };
+ const store = new Vuex.Store({
+ state,
+ });
+
+ wrapper = mount(Clusters, { localVue, store });
+ };
+
+ beforeEach(() => {
+ mountComponent({ loading: false });
+ });
+
+ describe('clusters table', () => {
+ it('displays a loader instead of the table while loading', () => {
+ mountComponent({ loading: true });
+ expect(findLoader().exists()).toBe(true);
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('displays a table component', () => {
+ expect(findTable().exists()).toBe(true);
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('renders the correct table headers', () => {
+ const tableHeaders = wrapper.vm.$options.fields;
+ const headers = findTable().findAll('th');
+
+ expect(headers.length).toBe(tableHeaders.length);
+
+ tableHeaders.forEach((headerText, i) =>
+ expect(headers.at(i).text()).toEqual(headerText.label),
+ );
+ });
+
+ it('should stack on smaller devices', () => {
+ expect(findTable().classes()).toContain('b-table-stacked-md');
+ });
+ });
+});
diff --git a/spec/frontend/clusters_list/store/actions_spec.js b/spec/frontend/clusters_list/store/actions_spec.js
new file mode 100644
index 00000000000..e903200bf1d
--- /dev/null
+++ b/spec/frontend/clusters_list/store/actions_spec.js
@@ -0,0 +1,50 @@
+import MockAdapter from 'axios-mock-adapter';
+import flashError from '~/flash';
+import testAction from 'helpers/vuex_action_helper';
+import axios from '~/lib/utils/axios_utils';
+import * as types from '~/clusters_list/store/mutation_types';
+import * as actions from '~/clusters_list/store/actions';
+
+jest.mock('~/flash.js');
+
+describe('Clusters store actions', () => {
+ describe('fetchClusters', () => {
+ let mock;
+ const endpoint = '/clusters';
+ const clusters = [{ name: 'test' }];
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => mock.restore());
+
+ it('should commit SET_CLUSTERS_DATA with received response', done => {
+ mock.onGet().reply(200, clusters);
+
+ testAction(
+ actions.fetchClusters,
+ { endpoint },
+ {},
+ [
+ { type: types.SET_CLUSTERS_DATA, payload: clusters },
+ { type: types.SET_LOADING_STATE, payload: false },
+ ],
+ [],
+ () => done(),
+ );
+ });
+
+ it('should show flash on API error', done => {
+ mock.onGet().reply(400, 'Not Found');
+
+ testAction(actions.fetchClusters, { endpoint }, {}, [], [], () => {
+ expect(flashError).toHaveBeenCalledWith(expect.stringMatching('error'));
+ done();
+ });
+ });
+ });
+});
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/spec/frontend/vue_mr_widget/mock_data.js b/spec/frontend/vue_mr_widget/mock_data.js
index d11756d712a..8ed153658fd 100644
--- a/spec/frontend/vue_mr_widget/mock_data.js
+++ b/spec/frontend/vue_mr_widget/mock_data.js
@@ -37,6 +37,7 @@ export default {
target_project_id: 19,
target_project_full_path: '/group2/project2',
merge_request_add_ci_config_path: '/group2/project2/new/pipeline',
+ new_project_pipeline_path: '/group2/project2/pipelines/new',
metrics: {
merged_by: {
name: 'Administrator',
diff --git a/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js b/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
index 796235be4c3..1906585af7b 100644
--- a/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
+++ b/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
@@ -102,5 +102,11 @@ describe('MergeRequestStore', () => {
expect(store.pipelinesEmptySvgPath).toBe('/path/to/svg');
});
+
+ it('should set newPipelinePath', () => {
+ store.setData({ ...mockData });
+
+ expect(store.newPipelinePath).toBe('/group2/project2/pipelines/new');
+ });
});
});
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 7740c34702b..78e80576aef 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -466,6 +466,7 @@ project:
- container_expiration_policy
- resource_groups
- autoclose_referenced_issues
+- status_page_setting
award_emoji:
- awardable
- user
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index beb6a0de0f6..31f8bcbfef0 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -162,6 +162,13 @@ describe MergeRequestWidgetEntity do
.to eq('Maintainer')
end
+ it 'has new pipeline path for project' do
+ project.add_maintainer(user)
+
+ expect(subject[:new_project_pipeline_path])
+ .to eq("/#{resource.project.full_path}/pipelines/new")
+ end
+
describe 'when source project is deleted' do
let(:project) { create(:project, :repository) }
let(:forked_project) { fork_project(project) }