Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b0980f5557
commit
c02e2a5ef6
|
@ -151,3 +151,20 @@ dependency_scanning:
|
|||
reports:
|
||||
dependency_scanning: gl-dependency-scanning-report.json
|
||||
expire_in: 1 week # GitLab-specific
|
||||
|
||||
license_scanning:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .reports:rules:license_scanning
|
||||
stage: test
|
||||
image:
|
||||
name: "registry.gitlab.com/gitlab-org/security-products/analyzers/license-finder:3"
|
||||
entrypoint: [""]
|
||||
needs: []
|
||||
script:
|
||||
- /run.sh analyze .
|
||||
artifacts:
|
||||
reports:
|
||||
license_scanning: gl-license-scanning-report.json
|
||||
expire_in: 1 week # GitLab-specific
|
||||
dependencies: []
|
||||
|
|
|
@ -719,6 +719,14 @@
|
|||
- <<: *if-master-schedule-nightly
|
||||
allow_failure: true
|
||||
|
||||
.reports:rules:license_scanning:
|
||||
rules:
|
||||
- if: '$LICENSE_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\blicense_scanning\b/'
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-qa-patterns
|
||||
allow_failure: true
|
||||
|
||||
################
|
||||
# Review rules #
|
||||
################
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -401,7 +401,7 @@ end
|
|||
|
||||
# Gems required in omnibus-gitlab pipeline
|
||||
group :development, :test, :omnibus do
|
||||
gem 'license_finder', '~> 5.4', require: false
|
||||
gem 'license_finder', '~> 6.0', require: false
|
||||
end
|
||||
|
||||
group :test do
|
||||
|
|
|
@ -643,9 +643,9 @@ GEM
|
|||
actionmailer (>= 3.2)
|
||||
letter_opener (~> 1.0)
|
||||
railties (>= 3.2)
|
||||
license_finder (5.4.0)
|
||||
license_finder (6.0.0)
|
||||
bundler
|
||||
rubyzip
|
||||
rubyzip (>= 1, < 3)
|
||||
thor
|
||||
toml (= 0.2.0)
|
||||
with_env (= 1.1.0)
|
||||
|
@ -1374,7 +1374,7 @@ DEPENDENCIES
|
|||
kramdown (~> 2.3.0)
|
||||
kubeclient (~> 4.6.0)
|
||||
letter_opener_web (~> 1.3.4)
|
||||
license_finder (~> 5.4)
|
||||
license_finder (~> 6.0)
|
||||
licensee (~> 8.9)
|
||||
lockbox (~> 0.3.3)
|
||||
lograge (~> 0.5)
|
||||
|
|
|
@ -5,3 +5,4 @@ export const EDITOR_LITE_INSTANCE_ERROR_NO_EL = __(
|
|||
);
|
||||
|
||||
export const URI_PREFIX = 'gitlab';
|
||||
export const CONTENT_UPDATE_DEBOUNCE = 250;
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
<script>
|
||||
import { GlAlert, GlLoadingIcon, GlToggle } from '@gitlab/ui';
|
||||
import { createNamespacedHelpers } from 'vuex';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { sprintf, s__ } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { LEGACY_FLAG, NEW_FLAG_ALERT } from '../constants';
|
||||
import store from '../store/index';
|
||||
import FeatureFlagForm from './form.vue';
|
||||
|
||||
const { mapState, mapActions } = createNamespacedHelpers('edit');
|
||||
|
||||
export default {
|
||||
store,
|
||||
components: {
|
||||
GlAlert,
|
||||
GlLoadingIcon,
|
||||
|
@ -20,14 +16,6 @@ export default {
|
|||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
environmentsEndpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -71,6 +59,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapState([
|
||||
'path',
|
||||
'error',
|
||||
'name',
|
||||
'description',
|
||||
|
@ -110,17 +99,10 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
this.setPath(this.path);
|
||||
return this.setEndpoint(this.endpoint).then(() => this.fetchFeatureFlag());
|
||||
return this.fetchFeatureFlag();
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'updateFeatureFlag',
|
||||
'setEndpoint',
|
||||
'setPath',
|
||||
'fetchFeatureFlag',
|
||||
'toggleActive',
|
||||
]),
|
||||
...mapActions(['updateFeatureFlag', 'fetchFeatureFlag', 'toggleActive']),
|
||||
dismissNewVersionFlagAlert() {
|
||||
this.userShouldSeeNewFlagAlert = false;
|
||||
axios.post(this.userCalloutsPath, {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
<script>
|
||||
import { createNamespacedHelpers } from 'vuex';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { GlButton, GlModalDirective, GlTabs } from '@gitlab/ui';
|
||||
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../constants';
|
||||
import FeatureFlagsTab from './feature_flags_tab.vue';
|
||||
import FeatureFlagsTable from './feature_flags_table.vue';
|
||||
import UserListsTable from './user_lists_table.vue';
|
||||
import store from '../store';
|
||||
import { s__ } from '~/locale';
|
||||
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
|
||||
import {
|
||||
|
@ -17,12 +16,9 @@ import {
|
|||
|
||||
import ConfigureFeatureFlagsModal from './configure_feature_flags_modal.vue';
|
||||
|
||||
const { mapState, mapActions } = createNamespacedHelpers('index');
|
||||
|
||||
const SCOPES = { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE };
|
||||
|
||||
export default {
|
||||
store,
|
||||
components: {
|
||||
FeatureFlagsTable,
|
||||
UserListsTable,
|
||||
|
@ -36,14 +32,6 @@ export default {
|
|||
GlModal: GlModalDirective,
|
||||
},
|
||||
props: {
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
projectId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
csrfToken: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -56,19 +44,10 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rotateInstanceIdPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
unleashApiUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
unleashApiInstanceId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
canUserConfigure: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
|
@ -144,23 +123,15 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
this.setFeatureFlagsEndpoint(this.endpoint);
|
||||
this.setFeatureFlagsOptions({ scope: this.scope, page: this.page });
|
||||
this.setProjectId(this.projectId);
|
||||
this.fetchFeatureFlags();
|
||||
this.fetchUserLists();
|
||||
this.setInstanceId(this.unleashApiInstanceId);
|
||||
this.setInstanceIdEndpoint(this.rotateInstanceIdPath);
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'setFeatureFlagsEndpoint',
|
||||
'setFeatureFlagsOptions',
|
||||
'fetchFeatureFlags',
|
||||
'fetchUserLists',
|
||||
'setInstanceIdEndpoint',
|
||||
'setInstanceId',
|
||||
'setProjectId',
|
||||
'rotateInstanceId',
|
||||
'toggleFeatureFlag',
|
||||
'deleteUserList',
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
NEW_VERSION_FLAG,
|
||||
LEGACY_FLAG,
|
||||
} from '../constants';
|
||||
import { createNewEnvironmentScope } from '../store/modules/helpers';
|
||||
import { createNewEnvironmentScope } from '../store/helpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<script>
|
||||
import { createNamespacedHelpers } from 'vuex';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { GlAlert } from '@gitlab/ui';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import store from '../store/index';
|
||||
import FeatureFlagForm from './form.vue';
|
||||
import {
|
||||
LEGACY_FLAG,
|
||||
|
@ -10,28 +9,17 @@ import {
|
|||
NEW_FLAG_ALERT,
|
||||
ROLLOUT_STRATEGY_ALL_USERS,
|
||||
} from '../constants';
|
||||
import { createNewEnvironmentScope } from '../store/modules/helpers';
|
||||
import { createNewEnvironmentScope } from '../store/helpers';
|
||||
|
||||
import featureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
const { mapState, mapActions } = createNamespacedHelpers('new');
|
||||
|
||||
export default {
|
||||
store,
|
||||
components: {
|
||||
GlAlert,
|
||||
FeatureFlagForm,
|
||||
},
|
||||
mixins: [featureFlagsMixin()],
|
||||
props: {
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
environmentsEndpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -64,7 +52,7 @@ export default {
|
|||
newFlagAlert: NEW_FLAG_ALERT,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['error']),
|
||||
...mapState(['error', 'path']),
|
||||
scopes() {
|
||||
return [
|
||||
createNewEnvironmentScope(
|
||||
|
@ -89,12 +77,8 @@ export default {
|
|||
return [{ name: ROLLOUT_STRATEGY_ALL_USERS, parameters: {}, scopes: [] }];
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setEndpoint(this.endpoint);
|
||||
this.setPath(this.path);
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['createFeatureFlag', 'setEndpoint', 'setPath']),
|
||||
...mapActions(['createFeatureFlag']),
|
||||
dismissNewVersionFlagAlert() {
|
||||
this.userShouldSeeNewFlagAlert = false;
|
||||
axios.post(this.userCalloutsPath, {
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
import Vue from 'vue';
|
||||
import EditFeatureFlag from '~/feature_flags/components/edit_feature_flag.vue';
|
||||
import Vuex from 'vuex';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import createStore from './store/edit';
|
||||
import EditFeatureFlag from './components/edit_feature_flag.vue';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default () => {
|
||||
const el = document.querySelector('#js-edit-feature-flag');
|
||||
const { environmentsScopeDocsPath, strategyTypeDocsPagePath } = el.dataset;
|
||||
const {
|
||||
environmentsScopeDocsPath,
|
||||
strategyTypeDocsPagePath,
|
||||
endpoint,
|
||||
featureFlagsPath,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
store: createStore({ endpoint, path: featureFlagsPath }),
|
||||
el,
|
||||
components: {
|
||||
EditFeatureFlag,
|
||||
},
|
||||
provide: {
|
||||
environmentsScopeDocsPath,
|
||||
strategyTypeDocsPagePath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('edit-feature-flag', {
|
||||
return createElement(EditFeatureFlag, {
|
||||
props: {
|
||||
endpoint: el.dataset.endpoint,
|
||||
path: el.dataset.featureFlagsPath,
|
||||
environmentsEndpoint: el.dataset.environmentsEndpoint,
|
||||
projectId: el.dataset.projectId,
|
||||
featureFlagIssuesEndpoint: el.dataset.featureFlagIssuesEndpoint,
|
||||
|
|
|
@ -1,41 +1,47 @@
|
|||
import Vue from 'vue';
|
||||
import FeatureFlagsComponent from '~/feature_flags/components/feature_flags.vue';
|
||||
import Vuex from 'vuex';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import FeatureFlagsComponent from './components/feature_flags.vue';
|
||||
import createStore from './store/index';
|
||||
|
||||
export default () =>
|
||||
new Vue({
|
||||
el: '#feature-flags-vue',
|
||||
components: {
|
||||
FeatureFlagsComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataset: document.querySelector(this.$options.el).dataset,
|
||||
};
|
||||
},
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default () => {
|
||||
const el = document.querySelector('#feature-flags-vue');
|
||||
|
||||
const {
|
||||
projectName,
|
||||
featureFlagsHelpPagePath,
|
||||
errorStateSvgPath,
|
||||
endpoint,
|
||||
projectId,
|
||||
unleashApiInstanceId,
|
||||
rotateInstanceIdPath,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
store: createStore({ endpoint, projectId, unleashApiInstanceId, rotateInstanceIdPath }),
|
||||
provide() {
|
||||
return {
|
||||
projectName: this.dataset.projectName,
|
||||
featureFlagsHelpPagePath: this.dataset.featureFlagsHelpPagePath,
|
||||
errorStateSvgPath: this.dataset.errorStateSvgPath,
|
||||
projectName,
|
||||
featureFlagsHelpPagePath,
|
||||
errorStateSvgPath,
|
||||
};
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('feature-flags-component', {
|
||||
return createElement(FeatureFlagsComponent, {
|
||||
props: {
|
||||
endpoint: this.dataset.endpoint,
|
||||
projectId: this.dataset.projectId,
|
||||
featureFlagsClientLibrariesHelpPagePath: this.dataset
|
||||
.featureFlagsClientLibrariesHelpPagePath,
|
||||
featureFlagsClientExampleHelpPagePath: this.dataset.featureFlagsClientExampleHelpPagePath,
|
||||
unleashApiUrl: this.dataset.unleashApiUrl,
|
||||
unleashApiInstanceId: this.dataset.unleashApiInstanceId || '',
|
||||
featureFlagsClientLibrariesHelpPagePath:
|
||||
el.dataset.featureFlagsClientLibrariesHelpPagePath,
|
||||
featureFlagsClientExampleHelpPagePath: el.dataset.featureFlagsClientExampleHelpPagePath,
|
||||
unleashApiUrl: el.dataset.unleashApiUrl,
|
||||
csrfToken: csrf.token,
|
||||
canUserConfigure: this.dataset.canUserAdminFeatureFlag,
|
||||
newFeatureFlagPath: this.dataset.newFeatureFlagPath,
|
||||
rotateInstanceIdPath: this.dataset.rotateInstanceIdPath,
|
||||
newUserListPath: this.dataset.newUserListPath,
|
||||
canUserConfigure: el.dataset.canUserAdminFeatureFlag,
|
||||
newFeatureFlagPath: el.dataset.newFeatureFlagPath,
|
||||
newUserListPath: el.dataset.newUserListPath,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
import Vue from 'vue';
|
||||
import NewFeatureFlag from '~/feature_flags/components/new_feature_flag.vue';
|
||||
import Vuex from 'vuex';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import createStore from './store/new';
|
||||
import NewFeatureFlag from './components/new_feature_flag.vue';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default () => {
|
||||
const el = document.querySelector('#js-new-feature-flag');
|
||||
const { environmentsScopeDocsPath, strategyTypeDocsPagePath } = el.dataset;
|
||||
const {
|
||||
environmentsScopeDocsPath,
|
||||
strategyTypeDocsPagePath,
|
||||
endpoint,
|
||||
featureFlagsPath,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
components: {
|
||||
NewFeatureFlag,
|
||||
},
|
||||
store: createStore({ endpoint, path: featureFlagsPath }),
|
||||
provide: {
|
||||
environmentsScopeDocsPath,
|
||||
strategyTypeDocsPagePath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('new-feature-flag', {
|
||||
return createElement(NewFeatureFlag, {
|
||||
props: {
|
||||
endpoint: el.dataset.endpoint,
|
||||
path: el.dataset.featureFlagsPath,
|
||||
environmentsEndpoint: el.dataset.environmentsEndpoint,
|
||||
projectId: el.dataset.projectId,
|
||||
userCalloutsPath: el.dataset.userCalloutsPath,
|
||||
|
|
|
@ -3,23 +3,9 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { deprecatedCreateFlash as createFlash } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import { NEW_VERSION_FLAG } from '../../../constants';
|
||||
import { NEW_VERSION_FLAG } from '../../constants';
|
||||
import { mapFromScopesViewModel, mapStrategiesToRails } from '../helpers';
|
||||
|
||||
/**
|
||||
* Commits mutation to set the main endpoint
|
||||
* @param {String} endpoint
|
||||
*/
|
||||
export const setEndpoint = ({ commit }, endpoint) => commit(types.SET_ENDPOINT, endpoint);
|
||||
|
||||
/**
|
||||
* Commits mutation to set the feature flag path.
|
||||
* Used to redirect the user after form submission
|
||||
*
|
||||
* @param {String} path
|
||||
*/
|
||||
export const setPath = ({ commit }, path) => commit(types.SET_PATH, path);
|
||||
|
||||
/**
|
||||
* Handles the edition of a feature flag.
|
||||
*
|
|
@ -0,0 +1,11 @@
|
|||
import Vuex from 'vuex';
|
||||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default data =>
|
||||
new Vuex.Store({
|
||||
actions,
|
||||
mutations,
|
||||
state: state(data),
|
||||
});
|
|
@ -1,6 +1,3 @@
|
|||
export const SET_ENDPOINT = 'SET_ENDPOINT';
|
||||
export const SET_PATH = 'SET_PATH';
|
||||
|
||||
export const REQUEST_UPDATE_FEATURE_FLAG = 'REQUEST_UPDATE_FEATURE_FLAG';
|
||||
export const RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS = 'RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS';
|
||||
export const RECEIVE_UPDATE_FEATURE_FLAG_ERROR = 'RECEIVE_UPDATE_FEATURE_FLAG_ERROR';
|
|
@ -1,14 +1,8 @@
|
|||
import * as types from './mutation_types';
|
||||
import { mapToScopesViewModel, mapStrategiesToViewModel } from '../helpers';
|
||||
import { LEGACY_FLAG } from '../../../constants';
|
||||
import { LEGACY_FLAG } from '../../constants';
|
||||
|
||||
export default {
|
||||
[types.SET_ENDPOINT](state, endpoint) {
|
||||
state.endpoint = endpoint;
|
||||
},
|
||||
[types.SET_PATH](state, path) {
|
||||
state.path = path;
|
||||
},
|
||||
[types.REQUEST_FEATURE_FLAG](state) {
|
||||
state.isLoading = true;
|
||||
},
|
|
@ -1,8 +1,8 @@
|
|||
import { LEGACY_FLAG } from '../../../constants';
|
||||
import { LEGACY_FLAG } from '../../constants';
|
||||
|
||||
export default () => ({
|
||||
endpoint: null,
|
||||
path: null,
|
||||
export default ({ path, endpoint }) => ({
|
||||
endpoint,
|
||||
path,
|
||||
isSendingRequest: false,
|
||||
error: [],
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
fetchPercentageParams,
|
||||
fetchUserIdParams,
|
||||
LEGACY_FLAG,
|
||||
} from '../../constants';
|
||||
} from '../constants';
|
||||
|
||||
/**
|
||||
* Converts raw scope objects fetched from the API into an array of scope
|
|
@ -1,18 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import indexModule from './modules/index';
|
||||
import newModule from './modules/new';
|
||||
import editModule from './modules/edit';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export const createStore = () =>
|
||||
new Vuex.Store({
|
||||
modules: {
|
||||
index: indexModule,
|
||||
new: newModule,
|
||||
edit: editModule,
|
||||
},
|
||||
});
|
||||
|
||||
export default createStore();
|
|
@ -2,19 +2,9 @@ import Api from '~/api';
|
|||
import * as types from './mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
export const setFeatureFlagsEndpoint = ({ commit }, endpoint) =>
|
||||
commit(types.SET_FEATURE_FLAGS_ENDPOINT, endpoint);
|
||||
|
||||
export const setFeatureFlagsOptions = ({ commit }, options) =>
|
||||
commit(types.SET_FEATURE_FLAGS_OPTIONS, options);
|
||||
|
||||
export const setInstanceIdEndpoint = ({ commit }, endpoint) =>
|
||||
commit(types.SET_INSTANCE_ID_ENDPOINT, endpoint);
|
||||
|
||||
export const setProjectId = ({ commit }, endpoint) => commit(types.SET_PROJECT_ID, endpoint);
|
||||
|
||||
export const setInstanceId = ({ commit }, instanceId) => commit(types.SET_INSTANCE_ID, instanceId);
|
||||
|
||||
export const fetchFeatureFlags = ({ state, dispatch }) => {
|
||||
dispatch('requestFeatureFlags');
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import Vuex from 'vuex';
|
||||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default data =>
|
||||
new Vuex.Store({
|
||||
actions,
|
||||
mutations,
|
||||
state: state(data),
|
||||
});
|
|
@ -1,8 +1,4 @@
|
|||
export const SET_FEATURE_FLAGS_ENDPOINT = 'SET_FEATURE_FLAGS_ENDPOINT';
|
||||
export const SET_FEATURE_FLAGS_OPTIONS = 'SET_FEATURE_FLAGS_OPTIONS';
|
||||
export const SET_INSTANCE_ID_ENDPOINT = 'SET_INSTANCE_ID_ENDPOINT';
|
||||
export const SET_INSTANCE_ID = 'SET_INSTANCE_ID';
|
||||
export const SET_PROJECT_ID = 'SET_PROJECT_ID';
|
||||
|
||||
export const REQUEST_FEATURE_FLAGS = 'REQUEST_FEATURE_FLAGS';
|
||||
export const RECEIVE_FEATURE_FLAGS_SUCCESS = 'RECEIVE_FEATURE_FLAGS_SUCCESS';
|
|
@ -1,7 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import * as types from './mutation_types';
|
||||
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
|
||||
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../../../constants';
|
||||
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../../constants';
|
||||
import { mapToScopesViewModel } from '../helpers';
|
||||
|
||||
const mapFlag = flag => ({ ...flag, scopes: mapToScopesViewModel(flag.scopes || []) });
|
||||
|
@ -23,21 +23,9 @@ const createPaginationInfo = (state, headers) => {
|
|||
};
|
||||
|
||||
export default {
|
||||
[types.SET_FEATURE_FLAGS_ENDPOINT](state, endpoint) {
|
||||
state.endpoint = endpoint;
|
||||
},
|
||||
[types.SET_FEATURE_FLAGS_OPTIONS](state, options = {}) {
|
||||
state.options = options;
|
||||
},
|
||||
[types.SET_INSTANCE_ID_ENDPOINT](state, endpoint) {
|
||||
state.rotateEndpoint = endpoint;
|
||||
},
|
||||
[types.SET_INSTANCE_ID](state, instance) {
|
||||
state.instanceId = instance;
|
||||
},
|
||||
[types.SET_PROJECT_ID](state, project) {
|
||||
state.projectId = project;
|
||||
},
|
||||
[types.REQUEST_FEATURE_FLAGS](state) {
|
||||
state.isLoading = true;
|
||||
},
|
|
@ -0,0 +1,18 @@
|
|||
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../../constants';
|
||||
|
||||
export default ({ endpoint, projectId, unleashApiInstanceId, rotateInstanceIdPath }) => ({
|
||||
[FEATURE_FLAG_SCOPE]: [],
|
||||
[USER_LIST_SCOPE]: [],
|
||||
alerts: [],
|
||||
count: {},
|
||||
pageInfo: { [FEATURE_FLAG_SCOPE]: {}, [USER_LIST_SCOPE]: {} },
|
||||
isLoading: true,
|
||||
hasError: false,
|
||||
endpoint,
|
||||
rotateEndpoint: rotateInstanceIdPath,
|
||||
instanceId: unleashApiInstanceId,
|
||||
isRotating: false,
|
||||
hasRotateError: false,
|
||||
options: {},
|
||||
projectId,
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
actions,
|
||||
mutations,
|
||||
state: state(),
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
actions,
|
||||
mutations,
|
||||
state: state(),
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../../../constants';
|
||||
|
||||
export default () => ({
|
||||
[FEATURE_FLAG_SCOPE]: [],
|
||||
[USER_LIST_SCOPE]: [],
|
||||
alerts: [],
|
||||
count: {},
|
||||
pageInfo: { [FEATURE_FLAG_SCOPE]: {}, [USER_LIST_SCOPE]: {} },
|
||||
isLoading: true,
|
||||
hasError: false,
|
||||
endpoint: null,
|
||||
rotateEndpoint: null,
|
||||
instanceId: '',
|
||||
isRotating: false,
|
||||
hasRotateError: false,
|
||||
options: {},
|
||||
projectId: '',
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
actions,
|
||||
mutations,
|
||||
state: state(),
|
||||
};
|
|
@ -1,6 +0,0 @@
|
|||
export default () => ({
|
||||
endpoint: null,
|
||||
path: null,
|
||||
isSendingRequest: false,
|
||||
error: [],
|
||||
});
|
|
@ -1,23 +1,9 @@
|
|||
import * as types from './mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { NEW_VERSION_FLAG } from '../../../constants';
|
||||
import { NEW_VERSION_FLAG } from '../../constants';
|
||||
import { mapFromScopesViewModel, mapStrategiesToRails } from '../helpers';
|
||||
|
||||
/**
|
||||
* Commits mutation to set the main endpoint
|
||||
* @param {String} endpoint
|
||||
*/
|
||||
export const setEndpoint = ({ commit }, endpoint) => commit(types.SET_ENDPOINT, endpoint);
|
||||
|
||||
/**
|
||||
* Commits mutation to set the feature flag path.
|
||||
* Used to redirect the user after form submission
|
||||
*
|
||||
* @param {String} path
|
||||
*/
|
||||
export const setPath = ({ commit }, path) => commit(types.SET_PATH, path);
|
||||
|
||||
/**
|
||||
* Handles the creation of a new feature flag.
|
||||
*
|
|
@ -0,0 +1,11 @@
|
|||
import Vuex from 'vuex';
|
||||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default data =>
|
||||
new Vuex.Store({
|
||||
actions,
|
||||
mutations,
|
||||
state: state(data),
|
||||
});
|
|
@ -1,6 +1,3 @@
|
|||
export const SET_ENDPOINT = 'SET_ENDPOINT';
|
||||
export const SET_PATH = 'SET_PATH';
|
||||
|
||||
export const REQUEST_CREATE_FEATURE_FLAG = 'REQUEST_CREATE_FEATURE_FLAG';
|
||||
export const RECEIVE_CREATE_FEATURE_FLAG_SUCCESS = 'RECEIVE_CREATE_FEATURE_FLAG_SUCCESS';
|
||||
export const RECEIVE_CREATE_FEATURE_FLAG_ERROR = 'RECEIVE_CREATE_FEATURE_FLAG_ERROR';
|
|
@ -1,12 +1,6 @@
|
|||
import * as types from './mutation_types';
|
||||
|
||||
export default {
|
||||
[types.SET_ENDPOINT](state, endpoint) {
|
||||
state.endpoint = endpoint;
|
||||
},
|
||||
[types.SET_PATH](state, path) {
|
||||
state.path = path;
|
||||
},
|
||||
[types.REQUEST_CREATE_FEATURE_FLAG](state) {
|
||||
state.isSendingRequest = true;
|
||||
state.error = [];
|
|
@ -0,0 +1,6 @@
|
|||
export default ({ endpoint, path }) => ({
|
||||
endpoint,
|
||||
path,
|
||||
isSendingRequest: false,
|
||||
error: [],
|
||||
});
|
|
@ -1,3 +1,3 @@
|
|||
import initEditFeatureFlags from '~/feature_flags/edit';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initEditFeatureFlags);
|
||||
initEditFeatureFlags();
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import initFeatureFlags from '~/feature_flags';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initFeatureFlags);
|
||||
initFeatureFlags();
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import initNewFeatureFlags from '~/feature_flags/new';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initNewFeatureFlags);
|
||||
initNewFeatureFlags();
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<script>
|
||||
import { debounce } from 'lodash';
|
||||
import Editor from '~/editor/editor_lite';
|
||||
import { CONTENT_UPDATE_DEBOUNCE } from '~/editor/constants';
|
||||
|
||||
function initEditorLite({ el, ...args }) {
|
||||
const editor = new Editor({
|
||||
scrollbar: {
|
||||
alwaysConsumeMouseWheel: false,
|
||||
},
|
||||
});
|
||||
|
||||
return editor.createInstance({
|
||||
el,
|
||||
...args,
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
fileName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
// This is used to help uniquely create a monaco model
|
||||
// even if two blob's share a file path.
|
||||
fileGlobalId: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
extensions: {
|
||||
type: [String, Array],
|
||||
required: false,
|
||||
default: () => null,
|
||||
},
|
||||
editorOptions: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
editor: null,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
fileName(newVal) {
|
||||
this.editor.updateModelLanguage(newVal);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.editor = initEditorLite({
|
||||
el: this.$refs.editor,
|
||||
blobPath: this.fileName,
|
||||
blobContent: this.value,
|
||||
blobGlobalId: this.fileGlobalId,
|
||||
extensions: this.extensions,
|
||||
...this.editorOptions,
|
||||
});
|
||||
|
||||
this.editor.onDidChangeModelContent(
|
||||
debounce(this.onFileChange.bind(this), CONTENT_UPDATE_DEBOUNCE),
|
||||
);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.editor.dispose();
|
||||
},
|
||||
methods: {
|
||||
onFileChange() {
|
||||
this.$emit('input', this.editor.getValue());
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="file-content code">
|
||||
<div id="editor" ref="editor" data-editor-loading @editor-ready="$emit('editor-ready')">
|
||||
<pre class="editor-loading-content">{{ value }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -6,6 +6,7 @@
|
|||
@import '@gitlab/at.js/dist/css/jquery.atwho';
|
||||
@import 'dropzone/dist/basic';
|
||||
@import 'select2';
|
||||
@import 'cropper/dist/cropper';
|
||||
|
||||
// GitLab UI framework
|
||||
@import 'framework';
|
||||
|
|
|
@ -241,7 +241,8 @@ class GroupsController < Groups::ApplicationController
|
|||
:two_factor_grace_period,
|
||||
:project_creation_level,
|
||||
:subgroup_creation_level,
|
||||
:default_branch_protection
|
||||
:default_branch_protection,
|
||||
:default_branch_name
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -301,7 +301,6 @@ module ProjectsHelper
|
|||
!disabled && !compact_mode
|
||||
end
|
||||
|
||||
# overridden in EE
|
||||
def settings_operations_available?
|
||||
can?(current_user, :read_environment, @project)
|
||||
end
|
||||
|
@ -755,6 +754,7 @@ module ProjectsHelper
|
|||
logs
|
||||
product_analytics
|
||||
metrics_dashboard
|
||||
tracings
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,19 @@
|
|||
class NamespaceSetting < ApplicationRecord
|
||||
belongs_to :namespace, inverse_of: :namespace_settings
|
||||
|
||||
validate :default_branch_name_content
|
||||
|
||||
NAMESPACE_SETTINGS_PARAMS = [:default_branch_name].freeze
|
||||
|
||||
self.primary_key = :namespace_id
|
||||
|
||||
def default_branch_name_content
|
||||
return if default_branch_name.nil?
|
||||
|
||||
if default_branch_name.blank?
|
||||
errors.add(:default_branch_name, "can not be an empty string")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
NamespaceSetting.prepend_if_ee('EE::NamespaceSetting')
|
||||
|
|
|
@ -23,6 +23,8 @@ module Groups
|
|||
|
||||
before_assignment_hook(group, params)
|
||||
|
||||
handle_namespace_settings
|
||||
|
||||
group.assign_attributes(params)
|
||||
|
||||
begin
|
||||
|
@ -40,6 +42,18 @@ module Groups
|
|||
|
||||
private
|
||||
|
||||
def handle_namespace_settings
|
||||
settings_params = params.slice(*::NamespaceSetting::NAMESPACE_SETTINGS_PARAMS)
|
||||
|
||||
return if settings_params.empty?
|
||||
|
||||
::NamespaceSetting::NAMESPACE_SETTINGS_PARAMS.each do |nsp|
|
||||
params.delete(nsp)
|
||||
end
|
||||
|
||||
::NamespaceSettings::UpdateService.new(current_user, group, settings_params).execute
|
||||
end
|
||||
|
||||
def valid_path_change_with_npm_packages?
|
||||
return true unless group.packages_feature_enabled?
|
||||
return true if params[:path].blank?
|
||||
|
|
|
@ -236,7 +236,7 @@
|
|||
= _('Logs')
|
||||
|
||||
- if project_nav_tab? :environments
|
||||
= render_if_exists "layouts/nav/sidebar/tracing_link"
|
||||
= render "layouts/nav/sidebar/tracing_link"
|
||||
|
||||
- if project_nav_tab?(:error_tracking)
|
||||
= nav_link(controller: :error_tracking) do
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
- return unless can?(current_user, :read_environment, @project)
|
||||
|
||||
- if project_nav_tab? :settings
|
||||
= nav_link(controller: :tracings, action: [:show]) do
|
||||
= link_to project_tracing_path(@project), title: _('Tracing') do
|
||||
%span
|
||||
= _('Tracing')
|
|
@ -0,0 +1,33 @@
|
|||
- setting = tracing_setting
|
||||
- has_jaeger_url = setting.external_url.present?
|
||||
|
||||
%section.settings.border-0.no-animate
|
||||
.settings-header{ :class => "border-top" }
|
||||
%h3{ :class => "h4" }
|
||||
= _("Jaeger tracing")
|
||||
%button.btn.gl-button.js-settings-toggle{ type: 'button' }
|
||||
= _('Expand')
|
||||
%p
|
||||
- if has_jaeger_url
|
||||
- tracing_link = link_to sanitize(setting.external_url, scrubber: Rails::Html::TextOnlyScrubber.new), target: "_blank", rel: 'noopener noreferrer' do
|
||||
%span
|
||||
= _('Tracing')
|
||||
= sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')
|
||||
- else
|
||||
- tracing_link = link_to project_tracing_path(@project) do
|
||||
%span
|
||||
= _('Tracing')
|
||||
= _("To open Jaeger and easily view tracing from GitLab, link the %{link} page to your server").html_safe % { link: tracing_link }
|
||||
.settings-content
|
||||
= form_for @project, url: project_settings_operations_path(@project), method: :patch do |f|
|
||||
= form_errors(@project)
|
||||
.form-group
|
||||
= f.fields_for :tracing_setting_attributes, setting do |form|
|
||||
= form.label :external_url, _('Jaeger URL'), class: 'label-bold'
|
||||
= form.url_field :external_url, class: 'form-control', placeholder: 'e.g. https://jaeger.mycompany.com'
|
||||
%p.form-text.text-muted
|
||||
- jaeger_help_url = "https://www.jaegertracing.io/docs/1.7/getting-started/"
|
||||
- link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url }
|
||||
- link_end_tag = "#{sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')}</a>".html_safe
|
||||
= _("For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}").html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
|
||||
= f.submit _('Save changes'), class: 'btn btn-success'
|
|
@ -8,5 +8,5 @@
|
|||
= render 'projects/settings/operations/prometheus', service: prometheus_service if Feature.enabled?(:settings_operations_prometheus_service)
|
||||
= render 'projects/settings/operations/metrics_dashboard'
|
||||
= render 'projects/settings/operations/grafana_integration'
|
||||
= render_if_exists 'projects/settings/operations/tracing'
|
||||
= render 'projects/settings/operations/tracing'
|
||||
= render_if_exists 'projects/settings/operations/status_page'
|
||||
|
|
|
@ -25,6 +25,6 @@
|
|||
= _("Incident")
|
||||
- if issuable.incident?
|
||||
%p.form-text.text-muted
|
||||
- incident_docs_url = help_page_path('operations/incident_management/incidents.md', anchor: 'create-and-manage-incidents-in-gitlab')
|
||||
- incident_docs_url = help_page_path('operations/incident_management/incidents.md')
|
||||
- incident_docs_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: incident_docs_url }
|
||||
= _('A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents.').html_safe % { incident_docs_start: incident_docs_start, incident_docs_end: '</a>'.html_safe }
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Handle the blacklisted ip error in the Go middleware
|
||||
merge_request: 44614
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added new editor-lite Vue component
|
||||
merge_request: 44577
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Move Tracing feature to Core
|
||||
merge_request: 44574
|
||||
author:
|
||||
type: added
|
|
@ -18,85 +18,85 @@
|
|||
:why: Bundler is MIT licensed but will sometimes fail in CI.
|
||||
:versions: []
|
||||
:when: 2016-05-02 06:42:08.045090000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- MIT
|
||||
- :who: Connor Shea
|
||||
:why: http://choosealicense.com/licenses/mit/
|
||||
:versions: []
|
||||
:when: 2016-04-17 21:12:24.558441000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- Apache 2.0
|
||||
- :who: Connor Shea
|
||||
:why: http://choosealicense.com/licenses/apache-2.0/
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:27:43.762702000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- ruby
|
||||
- :who: Connor Shea
|
||||
:why: https://github.com/ruby/ruby/blob/ruby_2_1/COPYING
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:31:54.498490000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- LGPL
|
||||
- :who: Connor Shea
|
||||
:why: http://www.gnu.org/licenses/license-list.html#LGPLv2.1
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:32:48.645841000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- ISC
|
||||
- :who: Connor Shea
|
||||
:why: http://www.gnu.org/licenses/license-list.html#ISC
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:42:01.894452000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- New BSD
|
||||
- :who: Connor Shea
|
||||
:why: https://opensource.org/licenses/BSD-3-Clause
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:44:38.246021000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- LGPL-2.1+
|
||||
- :who: Connor Shea
|
||||
:why: Equivalent to LGPL.
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:52:56.303239000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- BSD
|
||||
- :who: Connor Shea
|
||||
:why: https://opensource.org/licenses/BSD-2-Clause
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:55:09.796363000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- LGPLv2+
|
||||
- :who: Stan Hu
|
||||
:why: Equivalent to LGPLv2
|
||||
:versions: []
|
||||
:when: 2016-06-07 17:14:10.907682000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- Artistic 2.0
|
||||
- :who: Josh Frye
|
||||
:why: Disk/mount information display on Admin pages
|
||||
:versions: []
|
||||
:when: 2016-06-29 16:32:45.432113000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- Simplified BSD
|
||||
- :who: Douwe Maan
|
||||
:why: https://opensource.org/licenses/BSD-2-Clause
|
||||
:versions: []
|
||||
:when: 2016-07-26 21:24:07.248480000 Z
|
||||
- - :blacklist
|
||||
- - :restrict
|
||||
- GPLv2
|
||||
- :who: Connor Shea
|
||||
:why: GPL-licensed libraries cannot be linked to from non-GPL projects.
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:29:27.637336000 Z
|
||||
- - :blacklist
|
||||
- - :restrict
|
||||
- GPLv3
|
||||
- :who: Connor Shea
|
||||
:why: GPL-licensed libraries cannot be linked to from non-GPL projects.
|
||||
:versions: []
|
||||
:when: 2016-05-02 05:29:43.904715000 Z
|
||||
- - :blacklist
|
||||
- - :restrict
|
||||
- OSL-3.0
|
||||
- :who: Sean McGivern
|
||||
:why: The OSL license is a copyleft license
|
||||
|
@ -188,13 +188,13 @@
|
|||
:why: https://github.com/nodeca/pako/blob/master/LICENSE
|
||||
:versions: []
|
||||
:when: 2017-04-05 10:43:45.897720000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- Unlicense
|
||||
- :who: Nick Thomas <nick@gitlab.com>
|
||||
:why: https://gitlab.com/gitlab-com/organization/issues/116
|
||||
:versions: []
|
||||
:when: 2017-09-01 17:17:51.996511844 Z
|
||||
- - :blacklist
|
||||
- - :restrict
|
||||
- Facebook BSD+PATENTS
|
||||
- :who: Nick Thomas <nick@gitlab.com>
|
||||
:why: https://gitlab.com/gitlab-com/organization/issues/117
|
||||
|
@ -281,19 +281,19 @@
|
|||
:why: https://github.com/hexorx/countries/blob/master/LICENSE
|
||||
:versions: []
|
||||
:when: 2019-09-11 13:08:28.431132000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- "(MIT OR CC0-1.0)"
|
||||
- :who:
|
||||
:why:
|
||||
:versions: []
|
||||
:when: 2019-11-08 10:03:31.787226000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- CC0-1.0
|
||||
- :who: Thomas Randolph
|
||||
:why: This license is public domain
|
||||
:versions: []
|
||||
:when: 2020-06-03 05:04:44.632875345 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- 0BSD
|
||||
- :who: Natalia Tepluhina
|
||||
:why: This license is public domain
|
||||
|
@ -313,9 +313,15 @@
|
|||
:why: "https://github.com/cure53/DOMPurify/blob/main/LICENSE and https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31928#note_346604841"
|
||||
:versions: []
|
||||
:when: 2020-08-13 13:42:46.508082000 Z
|
||||
- - :whitelist
|
||||
- - :permit
|
||||
- Apache-2.0 WITH LLVM-exception
|
||||
- :who: Nathan Friend
|
||||
:why: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40670#note_403946372
|
||||
:versions: []
|
||||
:when: 2020-08-28 15:01:59.329048917 Z
|
||||
- - :approve
|
||||
- docutils
|
||||
- :who: Mo Khan
|
||||
:why: Used to generate documentation. https://pypi.org/project/docutils/0.13.1/
|
||||
:versions: []
|
||||
:when: 2020-10-05 20:22:55.955189491 Z
|
||||
|
|
|
@ -599,7 +599,6 @@ installations from source.
|
|||
|
||||
## Unicorn Logs
|
||||
|
||||
NOTE: **Note:**
|
||||
Starting with GitLab 13.0, Puma is the default web server used in GitLab
|
||||
all-in-one package based installations as well as GitLab Helm chart deployments.
|
||||
|
||||
|
@ -674,10 +673,8 @@ This log records:
|
|||
- Information whenever [Rack Attack](../security/rack_attack.md) registers an abusive request.
|
||||
- Requests over the [Rate Limit](../user/admin_area/settings/rate_limits_on_raw_endpoints.md) on raw endpoints.
|
||||
- [Protected paths](../user/admin_area/settings/protected_paths.md) abusive requests.
|
||||
|
||||
NOTE: **Note:**
|
||||
In GitLab versions [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/29239) and greater, user ID and username are also
|
||||
recorded on this log, if available.
|
||||
- In GitLab versions [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/29239) and greater,
|
||||
user ID and username, if available.
|
||||
|
||||
## `graphql_json.log`
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ or Grafana supplies package repositories (Yum/Apt) for easy installation.
|
|||
See [Grafana installation documentation](https://grafana.com/docs/grafana/latest/installation/)
|
||||
for detailed steps.
|
||||
|
||||
NOTE: **Note:**
|
||||
Before starting Grafana for the first time, set the admin user
|
||||
and password in `/etc/grafana/grafana.ini`. If you don't, the default password
|
||||
is `admin`.
|
||||
|
|
|
@ -25,7 +25,6 @@ To profile a request:
|
|||
curl --header 'X-Profile-Token: <token>' --header 'X-Profile-Mode: <mode>' "https://gitlab.example.com/group/project"
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
Profiled requests can take longer than usual.
|
||||
|
||||
After the request completes, you can view the profiling output from the
|
||||
|
|
|
@ -32,7 +32,7 @@ dashboard tool like [Grafana](https://grafana.com).
|
|||
## Configuring Prometheus
|
||||
|
||||
NOTE: **Note:**
|
||||
For installations from source, you'll have to install and configure it yourself.
|
||||
For installations from source, you must install and configure it yourself.
|
||||
|
||||
Prometheus and its exporters are on by default, starting with GitLab 9.0.
|
||||
Prometheus will run as the `gitlab-prometheus` user and listen on
|
||||
|
@ -179,7 +179,7 @@ The next step is to tell all the other nodes where the monitoring node is:
|
|||
take effect.
|
||||
|
||||
NOTE: **Note:**
|
||||
Once monitoring using Service Discovery is enabled with `consul['monitoring_service_discovery'] = true`,
|
||||
After monitoring using Service Discovery is enabled with `consul['monitoring_service_discovery'] = true`,
|
||||
ensure that `prometheus['scrape_configs']` is not set in `/etc/gitlab/gitlab.rb`. Setting both
|
||||
`consul['monitoring_service_discovery'] = true` and `prometheus['scrape_configs']` in `/etc/gitlab/gitlab.rb`
|
||||
will result in errors.
|
||||
|
@ -312,7 +312,6 @@ To use an external Prometheus server:
|
|||
|
||||
You can visit `http://localhost:9090` for the dashboard that Prometheus offers by default.
|
||||
|
||||
NOTE: **Note:**
|
||||
If SSL has been enabled on your GitLab instance, you may not be able to access
|
||||
Prometheus on the same browser as GitLab if using the same FQDN due to [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security). We plan to
|
||||
[provide access via GitLab](https://gitlab.com/gitlab-org/multi-user-prometheus), but in the interim there are
|
||||
|
|
|
@ -10,7 +10,7 @@ The [node exporter](https://github.com/prometheus/node_exporter) enables you to
|
|||
various machine resources such as memory, disk and CPU utilization.
|
||||
|
||||
NOTE: **Note:**
|
||||
For installations from source you'll have to install and configure it yourself.
|
||||
For installations from source you must install and configure it yourself.
|
||||
|
||||
To enable the node exporter:
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ The [PgBouncer exporter](https://github.com/prometheus-community/pgbouncer_expor
|
|||
you to measure various [PgBouncer](https://www.pgbouncer.org/) metrics.
|
||||
|
||||
NOTE: **Note:**
|
||||
For installations from source you'll have to install and configure it yourself.
|
||||
For installations from source you must install and configure it yourself.
|
||||
|
||||
To enable the PgBouncer exporter:
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
The [PostgreSQL Server Exporter](https://github.com/wrouesnel/postgres_exporter) allows you to export various PostgreSQL metrics.
|
||||
|
||||
NOTE: **Note:**
|
||||
For installations from source you will have to install and configure it yourself.
|
||||
For installations from source you must install and configure it yourself.
|
||||
|
||||
To enable the PostgreSQL Server Exporter:
|
||||
|
||||
|
@ -20,7 +20,6 @@ To enable the PostgreSQL Server Exporter:
|
|||
postgres_exporter['enable'] = true
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
If PostgreSQL Server Exporter is configured on a separate node, make sure that the local
|
||||
address is [listed in `trust_auth_cidr_addresses`](../../postgresql/replication_and_failover.md#network-information) or the
|
||||
exporter will not be able to connect to the database.
|
||||
|
|
|
@ -11,7 +11,7 @@ various [Redis](https://redis.io) metrics. For more information on what is expor
|
|||
[read the upstream documentation](https://github.com/oliver006/redis_exporter/blob/master/README.md#whats-exported).
|
||||
|
||||
NOTE: **Note:**
|
||||
For installations from source you'll have to install and configure it yourself.
|
||||
For installations from source you must install and configure it yourself.
|
||||
|
||||
To enable the Redis exporter:
|
||||
|
||||
|
|
|
@ -18,14 +18,11 @@ POST /environments/:id/metrics_dashboard/annotations/
|
|||
POST /clusters/:id/metrics_dashboard/annotations/
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
The value of `dashboard_path` will be treated as a CGI-escaped path, and automatically un-escaped.
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|:---------------|:---------------|:---------|:-----------------------------------------------------------------------------|
|
||||
| `dashboard_path` | string | yes | ID of the dashboard which needs to be annotated. |
|
||||
| `dashboard_path` | string | yes | ID of the dashboard which needs to be annotated. Treated as a CGI-escaped path, and automatically un-escaped. |
|
||||
| `starting_at` | string | yes | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z`. Timestamp marking start point of annotation. |
|
||||
| `ending_at` | string | no | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z`. Timestamp marking end point of annotation. When not supplied annotation will be displayed as single event at start point. |
|
||||
| `description` | string | yes | Description of the annotation. |
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
---
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Community members & roles
|
||||
|
||||
GitLab community members and their privileges/responsibilities.
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
---
|
||||
type: reference, dev
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Implement design & UI elements
|
||||
|
||||
For guidance on UX implementation at GitLab, please refer to our [Design System](https://design.gitlab.com/).
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
---
|
||||
type: reference, dev
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Contribute to GitLab
|
||||
|
||||
Thank you for your interest in contributing to GitLab. This guide details how
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
---
|
||||
type: reference, dev
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Issues workflow
|
||||
|
||||
## Issue tracker guidelines
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
---
|
||||
type: reference, dev
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Merge requests workflow
|
||||
|
||||
We welcome merge requests from everyone, with fixes and improvements
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
---
|
||||
type: reference, dev
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Style guides
|
||||
|
||||
## Editor/IDE styling standardization
|
||||
|
|
|
@ -6,10 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Distributed Tracing - development guidelines
|
||||
|
||||
NOTE: **Note:**
|
||||
Distributed Tracing in GitLab is currently considered **experimental**, as it has not yet been tested at scale on GitLab.com.
|
||||
|
||||
GitLab is instrumented for distributed tracing.
|
||||
GitLab is instrumented for distributed tracing. Distributed Tracing in GitLab is currently considered **experimental**, as it has not yet been tested at scale on GitLab.com.
|
||||
|
||||
According to [Open Tracing](https://opentracing.io/docs/overview/what-is-tracing/):
|
||||
|
||||
|
|
|
@ -20,10 +20,8 @@ You can sign up to the cloud hosted <https://sentry.io>, deploy your own [on-pre
|
|||
|
||||
### Enabling Sentry
|
||||
|
||||
NOTE: **Note:**
|
||||
You will need at least Maintainer [permissions](../user/permissions.md) to enable the Sentry integration.
|
||||
|
||||
GitLab provides an easy way to connect Sentry to your project:
|
||||
GitLab provides an easy way to connect Sentry to your project. You will need at
|
||||
least Maintainer [permissions](../user/permissions.md) to enable the Sentry integration.
|
||||
|
||||
1. Sign up to Sentry.io or [deploy your own](#deploying-sentry) Sentry instance.
|
||||
1. [Create](https://docs.sentry.io/product/sentry-basics/guides/integrate-frontend/create-new-project/) a new Sentry project. For each GitLab project that you want to integrate, we recommend that you create a new Sentry project.
|
||||
|
@ -47,9 +45,8 @@ You may also want to enable Sentry's GitLab integration by following the steps i
|
|||
## Error Tracking List
|
||||
|
||||
NOTE: **Note:**
|
||||
You will need at least Reporter [permissions](../user/permissions.md) to view the Error Tracking list.
|
||||
|
||||
You can find the Error Tracking list at **Operations > Error Tracking** in your project's sidebar.
|
||||
Users with at least Reporter [permissions](../user/permissions.md)
|
||||
can find the Error Tracking list at **Operations > Error Tracking** in your project's sidebar.
|
||||
Here, you can filter errors by title or by status (one of Ignored , Resolved, or Unresolved) and sort in descending order by Frequency, First Seen, or Last Seen. By default, the error list is ordered by Last Seen and filtered to Unresolved errors.
|
||||
|
||||
![Error Tracking list](img/error_tracking_list_v12_6.png)
|
||||
|
|
|
@ -40,13 +40,11 @@ in GitLab to examine alerts in action.
|
|||
|
||||
## Enable Alerts
|
||||
|
||||
NOTE: **Note:**
|
||||
You need at least Maintainer [permissions](../../user/permissions.md) to enable
|
||||
the Alerts feature.
|
||||
|
||||
There are several ways to accept alerts into your GitLab project. Enabling any
|
||||
of these methods enables the Alert list. After configuring alerts, visit
|
||||
**Operations > Alerts** in your project's sidebar to view the list of alerts.
|
||||
of these methods enables the Alert list. You need at least Maintainer
|
||||
[permissions](../../user/permissions.md) to enable the Alerts feature. After
|
||||
configuring alerts, visit **Operations > Alerts** in your project's sidebar to view
|
||||
the list of alerts.
|
||||
|
||||
### Enable GitLab-managed Prometheus alerts
|
||||
|
||||
|
@ -83,7 +81,6 @@ for requests to the alerts endpoint.
|
|||
|
||||
You can monitor alerts using a GitLab integration with [Opsgenie](https://www.atlassian.com/software/opsgenie).
|
||||
|
||||
NOTE: **Note:**
|
||||
If you enable the Opsgenie integration, you can't have other GitLab alert
|
||||
services, such as [Generic Alerts](generic_alerts.md) or Prometheus alerts,
|
||||
active at the same time.
|
||||
|
@ -168,14 +165,12 @@ about alert statuses.
|
|||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
|
||||
|
||||
The Alert detail view allows users to update the Alert assignee.
|
||||
GitLab supports only a single assignee per alert.
|
||||
|
||||
In large teams, where there is shared ownership of an alert, it can be
|
||||
difficult to track who is investigating and working on it. The Alert detail
|
||||
view enables you to update the Alert assignee:
|
||||
|
||||
NOTE: **Note:**
|
||||
GitLab supports only a single assignee per alert.
|
||||
|
||||
1. To display the list of current alerts, navigate to **Operations > Alerts**:
|
||||
|
||||
![Alert List View Assignee(s)](./img/alert_list_assignees_v13_1.png)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
|
@ -4,7 +4,7 @@ group: Health
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Create and manage incidents in GitLab
|
||||
# Incidents
|
||||
|
||||
While no configuration is required to use the [manual features](#create-an-incident-manually)
|
||||
of incident management, some simple [configuration](#configure-incidents) is needed to automate incident creation.
|
||||
|
@ -27,8 +27,7 @@ in your project's sidebar. The list contains the following metrics:
|
|||
- **{severity-low}** **Low - S4**
|
||||
- **{severity-unknown}** **Unknown**
|
||||
|
||||
NOTE: **Note:**
|
||||
Editing incident severity on the incident details page was
|
||||
[Editing incident severity](#incident-details) on the incident details page was
|
||||
[introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229402) in GitLab 13.4.
|
||||
|
||||
- **Incident** - The description of the incident, which attempts to capture the
|
||||
|
@ -45,13 +44,12 @@ The Incident list displays incidents sorted by incident created date.
|
|||
To see if a column is sortable, point your mouse at the header. Sortable columns
|
||||
display an arrow next to the column name.
|
||||
|
||||
Incidents share the [Issues API](../../user/project/issues/index.md).
|
||||
|
||||
TIP: **Tip:**
|
||||
For a live example of the incident list in action, visit this
|
||||
[demo project](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/incidents).
|
||||
|
||||
NOTE: **Note:**
|
||||
Incidents share the [Issues API](../../user/project/issues/index.md).
|
||||
|
||||
## Configure incidents
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4925) in GitLab Ultimate 11.11.
|
||||
|
@ -134,24 +132,55 @@ confirm that a GitLab issue is created from the incident.
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230847) in GitLab 13.4.
|
||||
|
||||
Users with at least Reporter [permissions](../../user/permissions.md) can view
|
||||
the Incident Details page. Navigate to **Operations > Incidents** in your project's
|
||||
sidebar, and select an incident from the list.
|
||||
|
||||
When you take any of these actions on an incident, GitLab logs a system note and
|
||||
displays it in the Incident Details view:
|
||||
|
||||
- Updating the severity of an incident
|
||||
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42358) in GitLab 13.5.)
|
||||
|
||||
For live examples of GitLab incidents, visit the `tanuki-inc` project's
|
||||
[incident list page](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/incidents).
|
||||
Click any incident in the list to display its incident details page.
|
||||
|
||||
### Summary
|
||||
|
||||
The summary section for incidents provides both critical details about and the
|
||||
contents of the issue template (if one was used). The highlighted bar at the top
|
||||
of the incident displays from left to right: the link to the original alert, the
|
||||
alert start time, and the event count. Beneath the highlight bar, GitLab
|
||||
displays a summary that includes the following fields:
|
||||
of the incident displays from left to right:
|
||||
|
||||
- The link to the original alert.
|
||||
- The alert start time.
|
||||
- The event count.
|
||||
|
||||
Beneath the highlight bar, GitLab displays a summary that includes the following fields:
|
||||
|
||||
- Start time
|
||||
- Severity
|
||||
- `full_query`
|
||||
- Monitoring tool
|
||||
|
||||
Comments are displayed in threads, but can be displayed chronologically
|
||||
[in a timeline view](#timeline-view).
|
||||
|
||||
### Alert details
|
||||
|
||||
Incidents show the details of linked alerts in a separate tab. To populate this
|
||||
tab, the incident must have been created with a linked alert. Incidents
|
||||
[created automatically](#configure-incidents) from alerts will have this
|
||||
[created automatically](#configure-incidents) from alerts have this
|
||||
field populated.
|
||||
|
||||
![Incident alert details](./img/incident_alert_details_v13_4.png)
|
||||
|
||||
### Timeline view
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227836) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
|
||||
|
||||
To quickly see the latest updates on an incident, click
|
||||
**{comments}** **Turn timeline view on** in the comment bar to display comments
|
||||
un-threaded and ordered chronologically, newest to oldest:
|
||||
|
||||
![Timeline view toggle](./img/timeline_view_toggle_v13_5.png)
|
||||
|
|
|
@ -37,11 +37,10 @@ To configure a GitLab Status Page you must:
|
|||
|
||||
### Configure GitLab with cloud provider information
|
||||
|
||||
To provide GitLab with the AWS account information needed to push content to your Status Page:
|
||||
|
||||
NOTE: **Note:**
|
||||
Only AWS S3 is supported as a deploy target.
|
||||
|
||||
To provide GitLab with the AWS account information needed to push content to your Status Page:
|
||||
|
||||
1. Sign into GitLab as a user with Maintainer or greater [permissions](../../user/permissions.md).
|
||||
1. Navigate to **{settings}** **Settings > Operations**. Next to **Status Page**,
|
||||
click **Expand**.
|
||||
|
@ -74,8 +73,6 @@ the necessary CI/CD variables to deploy the Status Page to AWS S3:
|
|||
1. Scroll to **Variables**, and click **Expand**.
|
||||
1. Add the following variables from your Amazon Console:
|
||||
- `S3_BUCKET_NAME` - The name of the Amazon S3 bucket.
|
||||
|
||||
NOTE: **Note:**
|
||||
If no bucket with the provided name exists, the first pipeline run creates
|
||||
one and configures it for
|
||||
[static website hosting](https://docs.aws.amazon.com/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html).
|
||||
|
@ -128,10 +125,7 @@ To publish an incident:
|
|||
1. Create an issue in the project you enabled the GitLab Status Page settings in.
|
||||
1. A [project or group owner](../../user/permissions.md) must use the
|
||||
`/publish` [quick action](../../user/project/quick_actions.md) to publish the
|
||||
issue to the GitLab Status Page.
|
||||
|
||||
NOTE: **Note:**
|
||||
Confidential issues can't be published.
|
||||
issue to the GitLab Status Page. Confidential issues can't be published.
|
||||
|
||||
A background worker publishes the issue onto the Status Page using the credentials
|
||||
you provided during setup. As part of publication, GitLab will:
|
||||
|
|
|
@ -78,7 +78,6 @@ For GitLab to associate your alerts with an [environment](../../ci/environments/
|
|||
you must configure a `gitlab_environment_name` label on the alerts you set up in
|
||||
Prometheus. The value of this should match the name of your environment in GitLab.
|
||||
|
||||
NOTE: **Note:**
|
||||
In GitLab versions 13.1 and greater, you can configure your manually configured
|
||||
Prometheus server to use the
|
||||
[Generic alerts integration](../incident_management/generic_alerts.md).
|
||||
|
|
|
@ -25,7 +25,6 @@ metrics about the [deployed application](../index.md#configure-prometheus-to-gat
|
|||
|
||||
## Kubernetes pod health dashboard
|
||||
|
||||
NOTE: **Note:**
|
||||
This dashboard requires Kubernetes v1.14 or higher, due to the
|
||||
[change in metric labels](https://github.com/kubernetes/kubernetes/pull/69099)
|
||||
in Kubernetes 1.14.
|
||||
|
|
|
@ -14,7 +14,6 @@ includes a few key metrics, but you can also define your own custom dashboards.
|
|||
You may create a [new dashboard from scratch](#add-a-new-dashboard-to-your-project)
|
||||
or [duplicate a GitLab-defined Prometheus dashboard](#duplicate-a-gitlab-defined-dashboard).
|
||||
|
||||
NOTE: **Note:**
|
||||
The metrics as defined below do not support alerts, unlike
|
||||
[custom metrics](../index.md#adding-custom-metrics).
|
||||
|
||||
|
@ -86,7 +85,7 @@ with the **Add Panel** page:
|
|||
1. Click **Add panel** in the **{ellipsis_v}** **More actions** menu.
|
||||
|
||||
NOTE: **Note:**
|
||||
You can add panel only to custom dashboards.
|
||||
You can only add panels to custom dashboards.
|
||||
|
||||
![Monitoring Dashboard actions menu with add panel item](img/actions_menu_create_add_panel_v13_3.png)
|
||||
1. In the **Define and preview panel** section, paste in the YAML you want to
|
||||
|
@ -100,16 +99,12 @@ with the **Add Panel** page:
|
|||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/37238) in GitLab 12.7.
|
||||
> - From [GitLab 12.8 onwards](https://gitlab.com/gitlab-org/gitlab/-/issues/39505), custom metrics are also duplicated when you duplicate a dashboard.
|
||||
|
||||
You can save a complete copy of a GitLab defined dashboard along with all custom metrics added to it.
|
||||
You can save a complete copy of a GitLab-defined dashboard along with all custom metrics added to it.
|
||||
The resulting `.yml` file can be customized and adapted to your project.
|
||||
You can decide to save the dashboard `.yml` file in the project's **default** branch or in a
|
||||
new branch.
|
||||
new branch. To duplicate a GitLab-defined dashboard:
|
||||
|
||||
1. Click **Duplicate current dashboard** in the **{ellipsis_v}** **More actions** menu.
|
||||
|
||||
NOTE: **Note:**
|
||||
You can duplicate only GitLab-defined dashboards.
|
||||
|
||||
1. Enter the filename and other information, such as the new commit's message, and click **Duplicate**.
|
||||
1. Select a branch to add your dashboard to:
|
||||
- *If you select your **default** branch,* the new dashboard becomes immediately available.
|
||||
|
|
|
@ -16,7 +16,10 @@ Queries that continue to use the old format will show no data.
|
|||
|
||||
## Predefined variables
|
||||
|
||||
GitLab supports a limited set of [CI variables](../../../ci/variables/README.md) in the Prometheus query. This is particularly useful for identifying a specific environment, for example with `ci_environment_slug`. The supported variables are:
|
||||
GitLab supports a limited set of [CI variables](../../../ci/variables/README.md)
|
||||
in the Prometheus query. This is particularly useful for identifying a specific
|
||||
environment, for example with `ci_environment_slug`. Variables for Prometheus queries
|
||||
must be lowercase. The supported variables are:
|
||||
|
||||
- `environment_filter`
|
||||
- `ci_environment_slug`
|
||||
|
@ -27,9 +30,6 @@ GitLab supports a limited set of [CI variables](../../../ci/variables/README.md)
|
|||
- `ci_environment_name`
|
||||
- `__range`
|
||||
|
||||
NOTE: **Note:**
|
||||
Variables for Prometheus queries must be lowercase.
|
||||
|
||||
### environment_filter
|
||||
|
||||
`environment_filter` is automatically expanded to `container_name!="POD",environment="ENVIRONMENT_NAME"`
|
||||
|
|
|
@ -17,8 +17,7 @@ metrics to others, and you want to have relevant information directly available.
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29691) in GitLab 12.2.
|
||||
|
||||
NOTE: **Note:**
|
||||
Requires [Kubernetes](../../user/project/integrations/prometheus_library/kubernetes.md) metrics.
|
||||
This feature requires [Kubernetes](../../user/project/integrations/prometheus_library/kubernetes.md) metrics.
|
||||
|
||||
Note: **Note:**
|
||||
In GitLab versions 13.3 and earlier, metrics dashboard links were in the form
|
||||
|
|
|
@ -12,14 +12,13 @@ Grafana metrics can be embedded in [GitLab Flavored Markdown](../../user/markdow
|
|||
|
||||
You can embed live [Grafana](https://docs.gitlab.com/omnibus/settings/grafana.html)
|
||||
charts in issues as a
|
||||
[direct linked rendered image](https://grafana.com/docs/grafana/latest/reference/share_panel/#direct-link-rendered-image).
|
||||
The **Direct link rendered image** sharing dialog within Grafana provides the link:
|
||||
[direct linked rendered image](https://grafana.com/docs/grafana/latest/reference/share_panel/#direct-link-rendered-image). Your Grafana instance must be available to the
|
||||
target user, either as a public dashboard or on the same network. The
|
||||
**Direct link rendered image** sharing dialog within Grafana provides the link:
|
||||
|
||||
![Grafana Direct Linked Rendered Image](img/grafana_live_embed.png)
|
||||
|
||||
NOTE: **Note:**
|
||||
For this embed to display correctly, the Grafana instance must be available to the
|
||||
target user, either as a public dashboard or on the same network.
|
||||
For this embed to display correctly, the
|
||||
|
||||
Copy the link and add an image tag as [inline HTML](../../user/markdown.md#inline-html)
|
||||
in your Markdown. You can tweak the query parameters to meet your needs, such as
|
||||
|
|
|
@ -24,7 +24,7 @@ Cron scheduling uses a series of five numbers, separated by spaces:
|
|||
# * * * * * <command to execute>
|
||||
```
|
||||
|
||||
[Source: [Wikipedia](https://en.wikipedia.org/wiki/Cron)]
|
||||
(Source: [Wikipedia](https://en.wikipedia.org/wiki/Cron))
|
||||
|
||||
In cron syntax, the asterisk (`*`) means 'every,' so the following cron strings
|
||||
are valid:
|
||||
|
|
|
@ -55,7 +55,6 @@ Currently, GitLab supports the following Kubernetes versions:
|
|||
- 1.14
|
||||
- 1.13 (deprecated, support ends on November 22, 2020)
|
||||
|
||||
NOTE: **Note:**
|
||||
Some GitLab features may support versions outside the range provided here.
|
||||
|
||||
### Adding and removing clusters
|
||||
|
@ -195,7 +194,6 @@ To clear the cache:
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24580) in GitLab 11.8.
|
||||
|
||||
NOTE: **Note:**
|
||||
You do not need to specify a base domain on cluster settings when using GitLab Serverless. The domain in that case
|
||||
will be specified as part of the Knative installation. See [Installing Applications](#installing-applications).
|
||||
|
||||
|
@ -223,13 +221,11 @@ Auto DevOps automatically detects, builds, tests, deploys, and monitors your
|
|||
applications.
|
||||
|
||||
To make full use of Auto DevOps (Auto Deploy, Auto Review Apps, and
|
||||
Auto Monitoring) you will need the Kubernetes project integration enabled.
|
||||
Auto Monitoring) you will need the Kubernetes project integration enabled, but
|
||||
Kubernetes clusters can be used without Auto DevOps.
|
||||
|
||||
[Read more about Auto DevOps](../../../topics/autodevops/index.md)
|
||||
|
||||
NOTE: **Note:**
|
||||
Kubernetes clusters can be used without Auto DevOps.
|
||||
|
||||
## Deploying to a Kubernetes cluster
|
||||
|
||||
A Kubernetes cluster can be the destination for a deployment job. If
|
||||
|
@ -252,20 +248,13 @@ GitLab CI/CD build environment.
|
|||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `KUBE_URL` | Equal to the API URL. |
|
||||
| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](add_remove_clusters.md#access-controls). |
|
||||
| `KUBE_NAMESPACE` | The namespace associated with the project's deployment service account. In the format `<project_name>-<project_id>-<environment>`. For GitLab-managed clusters, a matching namespace is automatically created by GitLab in the cluster. |
|
||||
| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](add_remove_clusters.md#access-controls). Prior to GitLab 11.5, `KUBE_TOKEN` was the Kubernetes token of the main service account of the cluster integration. |
|
||||
| `KUBE_NAMESPACE` | The namespace associated with the project's deployment service account. In the format `<project_name>-<project_id>-<environment>`. For GitLab-managed clusters, a matching namespace is automatically created by GitLab in the cluster. If your cluster was created before GitLab 12.2, the default `KUBE_NAMESPACE` is set to `<project_name>-<project_id>`. |
|
||||
| `KUBE_CA_PEM_FILE` | Path to a file containing PEM data. Only present if a custom CA bundle was specified. |
|
||||
| `KUBE_CA_PEM` | (**deprecated**) Raw PEM data. Only if a custom CA bundle was specified. |
|
||||
| `KUBECONFIG` | Path to a file containing `kubeconfig` for this deployment. CA bundle would be embedded if specified. This config also embeds the same token defined in `KUBE_TOKEN` so you likely will only need this variable. This variable name is also automatically picked up by `kubectl` so you won't actually need to reference it explicitly if using `kubectl`. |
|
||||
| `KUBE_INGRESS_BASE_DOMAIN` | From GitLab 11.8, this variable can be used to set a domain per cluster. See [cluster domains](#base-domain) for more information. |
|
||||
|
||||
NOTE: **Note:**
|
||||
Prior to GitLab 11.5, `KUBE_TOKEN` was the Kubernetes token of the main
|
||||
service account of the cluster integration.
|
||||
|
||||
NOTE: **Note:**
|
||||
If your cluster was created before GitLab 12.2, default `KUBE_NAMESPACE` will be set to `<project_name>-<project_id>`.
|
||||
|
||||
### Custom namespace
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) in GitLab 12.6.
|
||||
|
@ -290,7 +279,6 @@ You can customize the deployment namespace in a few ways:
|
|||
[`environment:kubernetes:namespace`](../../../ci/environments/index.md#configuring-kubernetes-deployments)
|
||||
in `.gitlab-ci.yml`.
|
||||
|
||||
NOTE: **Note:**
|
||||
When you customize the namespace, existing environments remain linked to their current
|
||||
namespaces until you [clear the cluster cache](#clearing-the-cluster-cache).
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ above the log file data, depending on your configuration:
|
|||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
To learn more about the Log Explorer, see [APM - Log Explorer](https://www.youtube.com/watch?v=hWclZHA7Dgw).
|
||||
|
||||
NOTE: **Note:**
|
||||
[Learn more about Kubernetes + GitLab](https://about.gitlab.com/solutions/kubernetes/).
|
||||
Everything you need to build, test, deploy, and run your application at scale.
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ Alternatively, if there is also no email address, the project creator is set as
|
|||
|
||||
User assignment by username is under development and not ready for production use. It is
|
||||
deployed behind a feature flag that is **disabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](<replace with path to>/administration/feature_flags.md)
|
||||
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||
can enable it.
|
||||
|
||||
To enable it:
|
||||
|
|
|
@ -8,11 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22133) in GitLab 11.7.
|
||||
|
||||
GitLab has support for automatically detecting and monitoring the Kubernetes NGINX Ingress controller. This is provided by leveraging the built-in Prometheus metrics included with Kubernetes NGINX Ingress controller [version 0.16.0](https://github.com/kubernetes/ingress-nginx/blob/master/Changelog.md#0160) onward.
|
||||
|
||||
NOTE: **Note:**
|
||||
NGINX Ingress versions prior to 0.16.0 offer an included [VTS Prometheus metrics exporter](nginx_ingress_vts.md), which exports metrics different than the built-in metrics.
|
||||
|
||||
GitLab has support for automatically detecting and monitoring the Kubernetes NGINX Ingress controller. This is provided by leveraging the built-in Prometheus metrics included with Kubernetes NGINX Ingress controller [version 0.16.0](https://github.com/kubernetes/ingress-nginx/blob/master/Changelog.md#0160) onward.
|
||||
|
||||
## Requirements
|
||||
|
||||
[Prometheus integration](../prometheus.md) must be active.
|
||||
|
|
|
@ -18,6 +18,15 @@ module Gitlab
|
|||
request = ActionDispatch::Request.new(env)
|
||||
|
||||
render_go_doc(request) || @app.call(env)
|
||||
rescue Gitlab::Auth::IpBlacklisted
|
||||
Gitlab::AuthLogger.error(
|
||||
message: 'Rack_Attack',
|
||||
env: :blocklist,
|
||||
remote_ip: request.ip,
|
||||
request_method: request.request_method,
|
||||
path: request.fullpath
|
||||
)
|
||||
Rack::Response.new('', 403).finish
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -201,7 +201,7 @@ module Gitlab
|
|||
personal_snippets: count(PersonalSnippet.where(last_28_days_time_period)),
|
||||
project_snippets: count(ProjectSnippet.where(last_28_days_time_period))
|
||||
}.merge(
|
||||
snowplow_event_counts(time_period: last_28_days_time_period(column: :collector_tstamp))
|
||||
snowplow_event_counts(last_28_days_time_period(column: :collector_tstamp))
|
||||
).tap do |data|
|
||||
data[:snippets] = data[:personal_snippets] + data[:project_snippets]
|
||||
end
|
||||
|
|
|
@ -2222,13 +2222,13 @@ msgstr ""
|
|||
msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
msgid "After that, you will not to be able to use merge approvals or code quality as well as many other features."
|
||||
msgid "After that, you will not be able to use merge approvals or code quality as well as many other features."
|
||||
msgstr ""
|
||||
|
||||
msgid "After that, you will not to be able to use merge approvals or epics as well as many other features."
|
||||
msgid "After that, you will not be able to use merge approvals or epics as well as many other features."
|
||||
msgstr ""
|
||||
|
||||
msgid "After that, you will not to be able to use merge approvals or epics as well as many security features."
|
||||
msgid "After that, you will not be able to use merge approvals or epics as well as many security features."
|
||||
msgstr ""
|
||||
|
||||
msgid "Alert"
|
||||
|
@ -29944,7 +29944,7 @@ msgstr ""
|
|||
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
|
||||
msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not be able to create issues or merge requests as well as many other features."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your CSV export has started. It will be emailed to %{email} when complete."
|
||||
|
|
|
@ -58,6 +58,10 @@ module QA
|
|||
click_element :retry_button
|
||||
end
|
||||
|
||||
def has_job_log?
|
||||
has_element? :job_log_content
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def loaded?(wait: 60)
|
||||
|
@ -70,3 +74,5 @@ module QA
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Job::Show.prepend_if_ee('QA::EE::Page::Project::Job::Show')
|
||||
|
|
|
@ -57,3 +57,5 @@ module QA
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Pipeline::Index.prepend_if_ee('QA::EE::Page::Project::Pipeline::Index')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Plan' do
|
||||
RSpec.describe 'Plan', :reliable do
|
||||
describe 'Related issues' do
|
||||
let(:project) do
|
||||
Resource::Project.fabricate_via_api! do |project|
|
||||
|
|
|
@ -551,6 +551,37 @@ RSpec.describe GroupsController, factory_default: :keep do
|
|||
end
|
||||
end
|
||||
|
||||
context "updating default_branch_name" do
|
||||
let(:example_branch_name) { "example_branch_name" }
|
||||
|
||||
subject(:update_action) do
|
||||
put :update,
|
||||
params: {
|
||||
id: group.to_param,
|
||||
group: { default_branch_name: example_branch_name }
|
||||
}
|
||||
end
|
||||
|
||||
it "updates the attribute" do
|
||||
expect { subject }
|
||||
.to change { group.namespace_settings.reload.default_branch_name }
|
||||
.from(nil)
|
||||
.to(example_branch_name)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:found)
|
||||
end
|
||||
|
||||
context "to empty string" do
|
||||
let(:example_branch_name) { '' }
|
||||
|
||||
it "does not update the attribute" do
|
||||
subject
|
||||
|
||||
expect(group.namespace_settings.reload.default_branch_name).not_to eq('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is a conflicting group path' do
|
||||
let!(:conflict_group) { create(:group, path: SecureRandom.hex(12) ) }
|
||||
let!(:old_name) { group.name }
|
||||
|
|
|
@ -43,31 +43,17 @@ RSpec.describe Projects::TracingsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'with valid license' do
|
||||
before do
|
||||
stub_licensed_features(tracing: true)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'with maintainer role' do
|
||||
it_behaves_like 'user with read access', :public
|
||||
it_behaves_like 'user with read access', :internal
|
||||
it_behaves_like 'user with read access', :private
|
||||
end
|
||||
|
||||
context 'without maintainer role' do
|
||||
it_behaves_like 'user without read access', :public
|
||||
it_behaves_like 'user without read access', :internal
|
||||
it_behaves_like 'user without read access', :private
|
||||
end
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'with invalid license' do
|
||||
before do
|
||||
stub_licensed_features(tracing: false)
|
||||
sign_in(user)
|
||||
end
|
||||
context 'with maintainer role' do
|
||||
it_behaves_like 'user with read access', :public
|
||||
it_behaves_like 'user with read access', :internal
|
||||
it_behaves_like 'user with read access', :private
|
||||
end
|
||||
|
||||
context 'without maintainer role' do
|
||||
it_behaves_like 'user without read access', :public
|
||||
it_behaves_like 'user without read access', :internal
|
||||
it_behaves_like 'user without read access', :private
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Tracings Content Security Policy' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
subject { response_headers['Content-Security-Policy'] }
|
||||
|
||||
before_all do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'when there is no global config' do
|
||||
before do
|
||||
expect_next_instance_of(Projects::TracingsController) do |controller|
|
||||
expect(controller).to receive(:current_content_security_policy)
|
||||
.and_return(ActionDispatch::ContentSecurityPolicy.new)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not add CSP directives' do
|
||||
visit project_tracing_path(project)
|
||||
|
||||
is_expected.to be_blank
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a global CSP config exists' do
|
||||
before do
|
||||
csp = ActionDispatch::ContentSecurityPolicy.new do |p|
|
||||
p.frame_src 'https://global-policy.com'
|
||||
end
|
||||
|
||||
expect_next_instance_of(Projects::TracingsController) do |controller|
|
||||
expect(controller).to receive(:current_content_security_policy).and_return(csp)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when external_url is set' do
|
||||
let!(:project_tracing_setting) { create(:project_tracing_setting, project: project) }
|
||||
|
||||
it 'overwrites frame-src' do
|
||||
visit project_tracing_path(project)
|
||||
|
||||
is_expected.to eq("frame-src https://example.com")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when external_url is not set' do
|
||||
it 'uses global policy' do
|
||||
visit project_tracing_path(project)
|
||||
|
||||
is_expected.to eq("frame-src https://global-policy.com")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,7 +6,7 @@ import { TEST_HOST } from 'spec/test_constants';
|
|||
import { mockTracking } from 'helpers/tracking_helper';
|
||||
import { LEGACY_FLAG, NEW_VERSION_FLAG, NEW_FLAG_ALERT } from '~/feature_flags/constants';
|
||||
import Form from '~/feature_flags/components/form.vue';
|
||||
import editModule from '~/feature_flags/store/modules/edit';
|
||||
import createStore from '~/feature_flags/store/edit';
|
||||
import EditFeatureFlag from '~/feature_flags/components/edit_feature_flag.vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
|
@ -20,10 +20,9 @@ describe('Edit feature flag form', () => {
|
|||
let wrapper;
|
||||
let mock;
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
edit: editModule,
|
||||
},
|
||||
const store = createStore({
|
||||
path: '/feature_flags',
|
||||
endpoint: `${TEST_HOST}/feature_flags.json`,
|
||||
});
|
||||
|
||||
const factory = (opts = {}) => {
|
||||
|
@ -34,8 +33,6 @@ describe('Edit feature flag form', () => {
|
|||
wrapper = shallowMount(EditFeatureFlag, {
|
||||
localVue,
|
||||
propsData: {
|
||||
endpoint: `${TEST_HOST}/feature_flags.json`,
|
||||
path: '/feature_flags',
|
||||
environmentsEndpoint: 'environments.json',
|
||||
projectId: '8',
|
||||
featureFlagIssuesEndpoint: `${TEST_HOST}/feature_flags/5/issues`,
|
||||
|
@ -105,7 +102,7 @@ describe('Edit feature flag form', () => {
|
|||
|
||||
describe('with error', () => {
|
||||
it('should render the error', () => {
|
||||
store.dispatch('edit/receiveUpdateFeatureFlagError', { message: ['The name is required'] });
|
||||
store.dispatch('receiveUpdateFeatureFlagError', { message: ['The name is required'] });
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.find('.alert-danger').exists()).toEqual(true);
|
||||
expect(wrapper.find('.alert-danger').text()).toContain('The name is required');
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { TEST_HOST } from 'spec/test_constants';
|
||||
import Api from '~/api';
|
||||
import { createStore } from '~/feature_flags/store';
|
||||
import createStore from '~/feature_flags/store/index';
|
||||
import FeatureFlagsTab from '~/feature_flags/components/feature_flags_tab.vue';
|
||||
import FeatureFlagsComponent from '~/feature_flags/components/feature_flags.vue';
|
||||
import FeatureFlagsTable from '~/feature_flags/components/feature_flags_table.vue';
|
||||
|
@ -14,19 +15,25 @@ import TablePagination from '~/vue_shared/components/pagination/table_pagination
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { getRequestData, userList } from '../mock_data';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('Feature flags', () => {
|
||||
const mockData = {
|
||||
endpoint: `${TEST_HOST}/endpoint.json`,
|
||||
csrfToken: 'testToken',
|
||||
featureFlagsClientLibrariesHelpPagePath: '/help/feature-flags#unleash-clients',
|
||||
featureFlagsClientExampleHelpPagePath: '/help/feature-flags#client-example',
|
||||
unleashApiUrl: `${TEST_HOST}/api/unleash`,
|
||||
unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
|
||||
canUserConfigure: true,
|
||||
canUserRotateToken: true,
|
||||
newFeatureFlagPath: 'feature-flags/new',
|
||||
newUserListPath: '/user-list/new',
|
||||
};
|
||||
|
||||
const mockState = {
|
||||
endpoint: `${TEST_HOST}/endpoint.json`,
|
||||
projectId: '8',
|
||||
unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
|
||||
};
|
||||
|
||||
let wrapper;
|
||||
|
@ -34,8 +41,9 @@ describe('Feature flags', () => {
|
|||
let store;
|
||||
|
||||
const factory = (propsData = mockData, fn = shallowMount) => {
|
||||
store = createStore();
|
||||
store = createStore(mockState);
|
||||
wrapper = fn(FeatureFlagsComponent, {
|
||||
localVue,
|
||||
store,
|
||||
propsData,
|
||||
provide: {
|
||||
|
@ -76,7 +84,6 @@ describe('Feature flags', () => {
|
|||
|
||||
describe('without permissions', () => {
|
||||
const propsData = {
|
||||
endpoint: `${TEST_HOST}/endpoint.json`,
|
||||
csrfToken: 'testToken',
|
||||
errorStateSvgPath: '/assets/illustrations/feature_flag.svg',
|
||||
featureFlagsHelpPagePath: '/help/feature-flags',
|
||||
|
@ -85,8 +92,6 @@ describe('Feature flags', () => {
|
|||
featureFlagsClientLibrariesHelpPagePath: '/help/feature-flags#unleash-clients',
|
||||
featureFlagsClientExampleHelpPagePath: '/help/feature-flags#client-example',
|
||||
unleashApiUrl: `${TEST_HOST}/api/unleash`,
|
||||
unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
|
||||
projectId: '8',
|
||||
};
|
||||
|
||||
beforeEach(done => {
|
||||
|
@ -134,7 +139,7 @@ describe('Feature flags', () => {
|
|||
let emptyState;
|
||||
|
||||
beforeEach(async () => {
|
||||
mock.onGet(mockData.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }).reply(
|
||||
mock.onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }).reply(
|
||||
200,
|
||||
{
|
||||
feature_flags: [],
|
||||
|
@ -154,8 +159,6 @@ describe('Feature flags', () => {
|
|||
});
|
||||
|
||||
it('should render the empty state', async () => {
|
||||
await axios.waitForAll();
|
||||
emptyState = wrapper.find(GlEmptyState);
|
||||
expect(emptyState.exists()).toBe(true);
|
||||
});
|
||||
|
||||
|
@ -182,7 +185,7 @@ describe('Feature flags', () => {
|
|||
describe('with paginated feature flags', () => {
|
||||
beforeEach(done => {
|
||||
mock
|
||||
.onGet(mockData.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
|
||||
.onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
|
||||
.replyOnce(200, getRequestData, {
|
||||
'x-next-page': '2',
|
||||
'x-page': '1',
|
||||
|
@ -218,7 +221,7 @@ describe('Feature flags', () => {
|
|||
const [flag] = table.props(FEATURE_FLAG_SCOPE);
|
||||
table.vm.$emit('toggle-flag', flag);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('index/toggleFeatureFlag', flag);
|
||||
expect(store.dispatch).toHaveBeenCalledWith('toggleFeatureFlag', flag);
|
||||
});
|
||||
|
||||
it('renders configure button', () => {
|
||||
|
@ -287,7 +290,7 @@ describe('Feature flags', () => {
|
|||
describe('unsuccessful request', () => {
|
||||
beforeEach(done => {
|
||||
mock
|
||||
.onGet(mockData.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
|
||||
.onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
|
||||
.replyOnce(500, {});
|
||||
Api.fetchFeatureFlagUserLists.mockRejectedValueOnce();
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { GlAlert } from '@gitlab/ui';
|
||||
import { TEST_HOST } from 'spec/test_constants';
|
||||
import Form from '~/feature_flags/components/form.vue';
|
||||
import newModule from '~/feature_flags/store/modules/new';
|
||||
import createStore from '~/feature_flags/store/new';
|
||||
import NewFeatureFlag from '~/feature_flags/components/new_feature_flag.vue';
|
||||
import {
|
||||
ROLLOUT_STRATEGY_ALL_USERS,
|
||||
|
@ -17,13 +17,15 @@ import { allUsersStrategy } from '../mock_data';
|
|||
const userCalloutId = 'feature_flags_new_version';
|
||||
const userCalloutsPath = `${TEST_HOST}/user_callouts`;
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('New feature flag form', () => {
|
||||
let wrapper;
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
new: newModule,
|
||||
},
|
||||
const store = createStore({
|
||||
endpoint: `${TEST_HOST}/feature_flags.json`,
|
||||
path: '/feature_flags',
|
||||
});
|
||||
|
||||
const factory = (opts = {}) => {
|
||||
|
@ -32,9 +34,8 @@ describe('New feature flag form', () => {
|
|||
wrapper = null;
|
||||
}
|
||||
wrapper = shallowMount(NewFeatureFlag, {
|
||||
localVue,
|
||||
propsData: {
|
||||
endpoint: `${TEST_HOST}/feature_flags.json`,
|
||||
path: '/feature_flags',
|
||||
environmentsEndpoint: 'environments.json',
|
||||
projectId: '8',
|
||||
showUserCallout: true,
|
||||
|
@ -63,7 +64,7 @@ describe('New feature flag form', () => {
|
|||
|
||||
describe('with error', () => {
|
||||
it('should render the error', () => {
|
||||
store.dispatch('new/receiveCreateFeatureFlagError', { message: ['The name is required'] });
|
||||
store.dispatch('receiveCreateFeatureFlagError', { message: ['The name is required'] });
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.find('.alert').exists()).toEqual(true);
|
||||
expect(wrapper.find('.alert').text()).toContain('The name is required');
|
||||
|
|
|
@ -2,8 +2,6 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { TEST_HOST } from 'spec/test_constants';
|
||||
import {
|
||||
setEndpoint,
|
||||
setPath,
|
||||
updateFeatureFlag,
|
||||
requestUpdateFeatureFlag,
|
||||
receiveUpdateFeatureFlagSuccess,
|
||||
|
@ -13,18 +11,15 @@ import {
|
|||
receiveFeatureFlagSuccess,
|
||||
receiveFeatureFlagError,
|
||||
toggleActive,
|
||||
} from '~/feature_flags/store/modules/edit/actions';
|
||||
import state from '~/feature_flags/store/modules/edit/state';
|
||||
import {
|
||||
mapStrategiesToRails,
|
||||
mapFromScopesViewModel,
|
||||
} from '~/feature_flags/store/modules/helpers';
|
||||
} from '~/feature_flags/store/edit/actions';
|
||||
import state from '~/feature_flags/store/edit/state';
|
||||
import { mapStrategiesToRails, mapFromScopesViewModel } from '~/feature_flags/store/helpers';
|
||||
import {
|
||||
NEW_VERSION_FLAG,
|
||||
LEGACY_FLAG,
|
||||
ROLLOUT_STRATEGY_ALL_USERS,
|
||||
} from '~/feature_flags/constants';
|
||||
import * as types from '~/feature_flags/store/modules/edit/mutation_types';
|
||||
import * as types from '~/feature_flags/store/edit/mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
@ -33,33 +28,7 @@ describe('Feature flags Edit Module actions', () => {
|
|||
let mockedState;
|
||||
|
||||
beforeEach(() => {
|
||||
mockedState = state();
|
||||
});
|
||||
|
||||
describe('setEndpoint', () => {
|
||||
it('should commit SET_ENDPOINT mutation', done => {
|
||||
testAction(
|
||||
setEndpoint,
|
||||
'feature_flags.json',
|
||||
mockedState,
|
||||
[{ type: types.SET_ENDPOINT, payload: 'feature_flags.json' }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setPath', () => {
|
||||
it('should commit SET_PATH mutation', done => {
|
||||
testAction(
|
||||
setPath,
|
||||
'/feature_flags',
|
||||
mockedState,
|
||||
[{ type: types.SET_PATH, payload: '/feature_flags' }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
mockedState = state({ endpoint: 'feature_flags.json', path: '/feature_flags' });
|
||||
});
|
||||
|
||||
describe('updateFeatureFlag', () => {
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
import state from '~/feature_flags/store/modules/edit/state';
|
||||
import mutations from '~/feature_flags/store/modules/edit/mutations';
|
||||
import * as types from '~/feature_flags/store/modules/edit/mutation_types';
|
||||
import state from '~/feature_flags/store/edit/state';
|
||||
import mutations from '~/feature_flags/store/edit/mutations';
|
||||
import * as types from '~/feature_flags/store/edit/mutation_types';
|
||||
|
||||
describe('Feature flags Edit Module Mutations', () => {
|
||||
let stateCopy;
|
||||
|
||||
beforeEach(() => {
|
||||
stateCopy = state();
|
||||
});
|
||||
|
||||
describe('SET_ENDPOINT', () => {
|
||||
it('should set endpoint', () => {
|
||||
mutations[types.SET_ENDPOINT](stateCopy, 'feature_flags.json');
|
||||
|
||||
expect(stateCopy.endpoint).toEqual('feature_flags.json');
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_PATH', () => {
|
||||
it('should set provided options', () => {
|
||||
mutations[types.SET_PATH](stateCopy, 'feature_flags');
|
||||
|
||||
expect(stateCopy.path).toEqual('feature_flags');
|
||||
});
|
||||
stateCopy = state({ endpoint: 'feature_flags.json', path: '/feature_flags' });
|
||||
});
|
||||
|
||||
describe('REQUEST_FEATURE_FLAG', () => {
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
createNewEnvironmentScope,
|
||||
mapStrategiesToViewModel,
|
||||
mapStrategiesToRails,
|
||||
} from '~/feature_flags/store/modules/helpers';
|
||||
} from '~/feature_flags/store/helpers';
|
||||
import {
|
||||
ROLLOUT_STRATEGY_ALL_USERS,
|
||||
ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
|
||||
|
|
|
@ -7,10 +7,7 @@ import {
|
|||
receiveFeatureFlagsSuccess,
|
||||
receiveFeatureFlagsError,
|
||||
fetchFeatureFlags,
|
||||
setFeatureFlagsEndpoint,
|
||||
setFeatureFlagsOptions,
|
||||
setInstanceIdEndpoint,
|
||||
setInstanceId,
|
||||
rotateInstanceId,
|
||||
requestRotateInstanceId,
|
||||
receiveRotateInstanceIdSuccess,
|
||||
|
@ -26,10 +23,10 @@ import {
|
|||
deleteUserList,
|
||||
receiveDeleteUserListError,
|
||||
clearAlert,
|
||||
} from '~/feature_flags/store/modules/index/actions';
|
||||
import { mapToScopesViewModel } from '~/feature_flags/store/modules/helpers';
|
||||
import state from '~/feature_flags/store/modules/index/state';
|
||||
import * as types from '~/feature_flags/store/modules/index/mutation_types';
|
||||
} from '~/feature_flags/store/index/actions';
|
||||
import { mapToScopesViewModel } from '~/feature_flags/store/helpers';
|
||||
import state from '~/feature_flags/store/index/state';
|
||||
import * as types from '~/feature_flags/store/index/mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { getRequestData, rotateData, featureFlag, userList } from '../../mock_data';
|
||||
|
||||
|
@ -39,20 +36,7 @@ describe('Feature flags actions', () => {
|
|||
let mockedState;
|
||||
|
||||
beforeEach(() => {
|
||||
mockedState = state();
|
||||
});
|
||||
|
||||
describe('setFeatureFlagsEndpoint', () => {
|
||||
it('should commit SET_FEATURE_FLAGS_ENDPOINT mutation', done => {
|
||||
testAction(
|
||||
setFeatureFlagsEndpoint,
|
||||
'feature_flags.json',
|
||||
mockedState,
|
||||
[{ type: types.SET_FEATURE_FLAGS_ENDPOINT, payload: 'feature_flags.json' }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
mockedState = state({});
|
||||
});
|
||||
|
||||
describe('setFeatureFlagsOptions', () => {
|
||||
|
@ -68,32 +52,6 @@ describe('Feature flags actions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('setInstanceIdEndpoint', () => {
|
||||
it('should commit SET_INSTANCE_ID_ENDPOINT mutation', done => {
|
||||
testAction(
|
||||
setInstanceIdEndpoint,
|
||||
'instance_id.json',
|
||||
mockedState,
|
||||
[{ type: types.SET_INSTANCE_ID_ENDPOINT, payload: 'instance_id.json' }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setInstanceId', () => {
|
||||
it('should commit SET_INSTANCE_ID mutation', done => {
|
||||
testAction(
|
||||
setInstanceId,
|
||||
'test_instance_id',
|
||||
mockedState,
|
||||
[{ type: types.SET_INSTANCE_ID, payload: 'test_instance_id' }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchFeatureFlags', () => {
|
||||
let mock;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue