Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-09 03:11:51 +00:00
parent 4d58268e54
commit fae5be5632
33 changed files with 139 additions and 540 deletions

View File

@ -43,9 +43,6 @@ export const getProjectValueStreamStages = (requestPath, valueStreamId) => {
export const getProjectValueStreamStageData = ({ requestPath, stageId, params }) =>
axios.get(joinPaths(requestPath, 'events', stageId), { params });
export const getProjectValueStreamMetrics = (requestPath, params) =>
axios.get(requestPath, { params });
/**
* Dedicated project VSA paths
*/

View File

@ -47,15 +47,13 @@ export default {
'selectedStage',
'selectedStageEvents',
'selectedStageError',
'stages',
'summary',
'permissions',
'stageCounts',
'endpoints',
'features',
'createdBefore',
'createdAfter',
'pagination',
'hasNoAccessError',
]),
...mapGetters(['pathNavigationData', 'filterParams']),
isLoaded() {
@ -69,9 +67,7 @@ export default {
return !this.isLoadingStage && this.isEmptyStage;
},
displayNoAccess() {
return (
!this.isLoadingStage && this.selectedStage?.id && !this.isUserAllowed(this.selectedStage.id)
);
return !this.isLoadingStage && this.hasNoAccessError;
},
displayPathNavigation() {
return this.isLoading || (this.selectedStage && this.pathNavigationData.length);
@ -137,10 +133,6 @@ export default {
this.isOverviewDialogDismissed = true;
setCookie(OVERVIEW_DIALOG_COOKIE, '1');
},
isUserAllowed(id) {
const { permissions } = this;
return Boolean(permissions?.[id]);
},
onHandleUpdatePagination(data) {
this.updateStageTablePagination(data);
},

View File

@ -1,7 +1,6 @@
import {
getProjectValueStreamStages,
getProjectValueStreams,
getProjectValueStreamMetrics,
getValueStreamStageMedian,
getValueStreamStageRecords,
getValueStreamStageCounts,
@ -52,24 +51,6 @@ export const fetchValueStreams = ({ commit, dispatch, state }) => {
commit(types.RECEIVE_VALUE_STREAMS_ERROR, status);
});
};
export const fetchCycleAnalyticsData = ({
state: {
endpoints: { requestPath },
},
getters: { legacyFilterParams },
commit,
}) => {
commit(types.REQUEST_CYCLE_ANALYTICS_DATA);
return getProjectValueStreamMetrics(requestPath, legacyFilterParams)
.then(({ data }) => commit(types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS, data))
.catch(() => {
commit(types.RECEIVE_CYCLE_ANALYTICS_DATA_ERROR);
createFlash({
message: __('There was an error while fetching value stream summary data.'),
});
});
};
export const fetchStageData = ({
getters: { requestParams, filterParams, paginationParams },
@ -153,7 +134,6 @@ export const fetchStageCountValues = ({
export const fetchValueStreamStageData = ({ dispatch }) =>
Promise.all([
dispatch('fetchCycleAnalyticsData'),
dispatch('fetchStageData'),
dispatch('fetchStageMedians'),
dispatch('fetchStageCountValues'),
@ -178,6 +158,11 @@ export const setDateRange = ({ dispatch, commit }, { createdAfter, createdBefore
};
export const setInitialStage = ({ dispatch, commit, state: { stages } }, stage) => {
if (!stages.length && !stage) {
commit(types.SET_NO_ACCESS_ERROR);
return null;
}
const selectedStage = stage || stages[0];
commit(types.SET_SELECTED_STAGE, selectedStage);
return dispatch('fetchValueStreamStageData');

View File

@ -49,12 +49,6 @@ const dateRangeParams = ({ createdAfter, createdBefore }) => ({
created_before: createdBefore ? dateFormat(createdBefore, dateFormats.isoDate) : null,
});
export const legacyFilterParams = ({ daysInPast }) => {
return {
'cycle_analytics[start_date]': daysInPast,
};
};
export const filterParams = (state) => {
return {
...filterBarParams(state),

View File

@ -5,6 +5,7 @@ export const SET_SELECTED_VALUE_STREAM = 'SET_SELECTED_VALUE_STREAM';
export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE';
export const SET_DATE_RANGE = 'SET_DATE_RANGE';
export const SET_PAGINATION = 'SET_PAGINATION';
export const SET_NO_ACCESS_ERROR = 'SET_NO_ACCESS_ERROR';
export const REQUEST_VALUE_STREAMS = 'REQUEST_VALUE_STREAMS';
export const RECEIVE_VALUE_STREAMS_SUCCESS = 'RECEIVE_VALUE_STREAMS_SUCCESS';
@ -14,10 +15,6 @@ export const REQUEST_VALUE_STREAM_STAGES = 'REQUEST_VALUE_STREAM_STAGES';
export const RECEIVE_VALUE_STREAM_STAGES_SUCCESS = 'RECEIVE_VALUE_STREAM_STAGES_SUCCESS';
export const RECEIVE_VALUE_STREAM_STAGES_ERROR = 'RECEIVE_VALUE_STREAM_STAGES_ERROR';
export const REQUEST_CYCLE_ANALYTICS_DATA = 'REQUEST_CYCLE_ANALYTICS_DATA';
export const RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS = 'RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS';
export const RECEIVE_CYCLE_ANALYTICS_DATA_ERROR = 'RECEIVE_CYCLE_ANALYTICS_DATA_ERROR';
export const REQUEST_STAGE_DATA = 'REQUEST_STAGE_DATA';
export const RECEIVE_STAGE_DATA_SUCCESS = 'RECEIVE_STAGE_DATA_SUCCESS';
export const RECEIVE_STAGE_DATA_ERROR = 'RECEIVE_STAGE_DATA_ERROR';

View File

@ -41,6 +41,9 @@ export default {
direction: direction || PAGINATION_SORT_DIRECTION_DESC,
});
},
[types.SET_NO_ACCESS_ERROR](state) {
state.hasNoAccessError = true;
},
[types.REQUEST_VALUE_STREAMS](state) {
state.valueStreams = [];
},
@ -59,23 +62,12 @@ export default {
[types.RECEIVE_VALUE_STREAM_STAGES_ERROR](state) {
state.stages = [];
},
[types.REQUEST_CYCLE_ANALYTICS_DATA](state) {
state.isLoading = true;
state.hasError = false;
},
[types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS](state, data) {
state.permissions = data?.permissions || {};
state.hasError = false;
},
[types.RECEIVE_CYCLE_ANALYTICS_DATA_ERROR](state) {
state.isLoading = false;
state.hasError = true;
},
[types.REQUEST_STAGE_DATA](state) {
state.isLoadingStage = true;
state.isEmptyStage = false;
state.selectedStageEvents = [];
state.hasError = false;
state.hasNoAccessError = false;
},
[types.RECEIVE_STAGE_DATA_SUCCESS](state, events = []) {
state.isLoadingStage = false;
@ -83,13 +75,14 @@ export default {
state.selectedStageEvents = events.map((ev) =>
convertObjectPropsToCamelCase(ev, { deep: true }),
);
state.hasError = false;
state.hasNoAccessError = false;
},
[types.RECEIVE_STAGE_DATA_ERROR](state, error) {
state.isLoadingStage = false;
state.isEmptyStage = true;
state.selectedStageEvents = [];
state.hasError = true;
state.selectedStageError = error;
},
[types.REQUEST_STAGE_MEDIANS](state) {

View File

@ -10,9 +10,7 @@ export default () => ({
createdAfter: null,
createdBefore: null,
stages: [],
summary: [],
analytics: [],
stats: [],
valueStreams: [],
selectedValueStream: {},
selectedStage: {},
@ -20,11 +18,10 @@ export default () => ({
selectedStageError: '',
medians: {},
stageCounts: {},
hasError: false,
hasNoAccessError: false,
isLoading: false,
isLoadingStage: false,
isEmptyStage: false,
permissions: {},
pagination: {
page: null,
hasNextPage: false,

View File

@ -200,8 +200,7 @@ class FinalizeCiBuildsBigintConversion < Gitlab::Database::Migration[1.0]
column: column,
target_column: :id_convert_to_bigint,
name: temporary_name,
on_delete: on_delete,
reverse_lock_order: true)
on_delete: on_delete)
end
end
@ -214,9 +213,6 @@ class FinalizeCiBuildsBigintConversion < Gitlab::Database::Migration[1.0]
next unless foreign_key_exists?(from_table, TABLE_NAME, column: column, primary_key: :id, name: existing_name)
with_lock_retries do
# Explicitly lock table in order of parent, child to attempt to avoid deadlocks
execute "LOCK TABLE #{TABLE_NAME}, #{from_table} IN ACCESS EXCLUSIVE MODE"
temporary_name = "#{existing_name}_tmp"
remove_foreign_key(from_table, TABLE_NAME, column: column, primary_key: :id, name: existing_name)

View File

@ -1,21 +1,8 @@
# frozen_string_literal: true
class SchedulePopulateStatusColumnOfSecurityScans < Gitlab::Database::Migration[1.0]
MIGRATION = 'PopulateStatusColumnOfSecurityScans'
BATCH_SIZE = 10_000
DELAY_INTERVAL = 2.minutes
disable_ddl_transaction!
def up
return unless Gitlab.ee?
queue_background_migration_jobs_by_range_at_intervals(
define_batchable_model('security_scans'),
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE
)
# no-op
end
def down

View File

@ -1,20 +1,8 @@
# frozen_string_literal: true
class ScheduleBackfillCiNamespaceMirrors < Gitlab::Database::Migration[1.0]
MIGRATION = 'BackfillCiNamespaceMirrors'
BATCH_SIZE = 10_000
DELAY_INTERVAL = 2.minutes
disable_ddl_transaction!
def up
queue_background_migration_jobs_by_range_at_intervals(
Gitlab::BackgroundMigration::BackfillCiNamespaceMirrors::Namespace.base_query,
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE,
track_jobs: true
)
# no-op
end
def down

View File

@ -1,20 +1,8 @@
# frozen_string_literal: true
class ScheduleBackfillCiProjectMirrors < Gitlab::Database::Migration[1.0]
MIGRATION = 'BackfillCiProjectMirrors'
BATCH_SIZE = 10_000
DELAY_INTERVAL = 2.minutes
disable_ddl_transaction!
def up
queue_background_migration_jobs_by_range_at_intervals(
Gitlab::BackgroundMigration::BackfillCiProjectMirrors::Project.base_query,
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE,
track_jobs: true
)
# no-op
end
def down

View File

@ -1,12 +1,8 @@
# frozen_string_literal: true
class CleanupBackfillCiNamespaceMirrors < Gitlab::Database::Migration[1.0]
MIGRATION = 'BackfillCiNamespaceMirrors'
disable_ddl_transaction!
def up
finalize_background_migration(MIGRATION)
# no-op
end
def down

View File

@ -1,12 +1,8 @@
# frozen_string_literal: true
class CleanupBackfillCiProjectMirrors < Gitlab::Database::Migration[1.0]
MIGRATION = 'BackfillCiProjectMirrors'
disable_ddl_transaction!
def up
finalize_background_migration(MIGRATION)
# no-op
end
def down

View File

@ -1303,14 +1303,26 @@ process repositories that do not pass consistency checks.
For Omnibus GitLab installations, edit `/etc/gitlab/gitlab.rb` and set the
following keys (in this example, to disable the `hasDotgit` consistency check):
```ruby
ignored_git_errors = ["hasDotgit = ignore"]
omnibus_gitconfig['system'] = {
"fsck" => ignored_git_errors,
"fetch.fsck" => ignored_git_errors,
"receive.fsck" => ignored_git_errors,
}
```
- In [GitLab 15.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6800) and later:
```ruby
gitaly['gitconfig'] = [
{ key: "fsck.hasDotgit", value: "ignore" },
{ key: "fetch.fsck.hasDotgit", value: "ignore" },
{ key: "receive.fsck.hasDotgit", value: "ignore "},
]
```
- In GitLab 15.2 and earlier (legacy method):
```ruby
ignored_git_errors = ["hasDotgit = ignore"]
omnibus_gitconfig['system'] = {
"fsck" => ignored_git_errors,
"fetch.fsck" => ignored_git_errors,
"receive.fsck" => ignored_git_errors,
}
```
For source installs, edit the Gitaly configuration (`gitaly.toml`) to do the
equivalent:

View File

@ -80,7 +80,7 @@ separated by spaces.
To copy the name of a single failed test:
1. Expand the **Test summary** panel by selecting **Show test summary details** (**{angle-down}**).
1. Expand the **Test summary** panel by selecting **Show test summary details** (**{chevron-lg-down}**).
1. Select the test you want to review.
1. Select **Copy test name to rerun locally** (**{copy-to-clipboard}**).

View File

@ -208,7 +208,27 @@ See [the documentation](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/p
Everything in `app/serializers`, used for presenting the response to a request,
typically in JSON.
### Model class methods
### Models
Classes and modules in `app/models` represent domain concepts that encapsulate both
[data and behavior](https://en.wikipedia.org/wiki/Domain_model).
These classes can interact directly with a data store (like ActiveRecord models) or
can be a thin wrapper (Plain Old Ruby Objects) on top of ActiveRecord models to express a
richer domain concept.
[Entities and Value Objects](https://martinfowler.com/bliki/EvansClassification.html)
that represent domain concepts are considered domain models.
Some examples:
- [`DesignManagement::DesignAtVersion`](https://gitlab.com/gitlab-org/gitlab/-/blob/b62ce98cff8e0530210670f9cb0314221181b77f/app/models/design_management/design_at_version.rb)
is a model that leverages validations to combine designs and versions.
- [`Ci::Minutes::Usage`](https://gitlab.com/gitlab-org/gitlab/-/blob/ec52f19f7325410177c00fef06379f55ab7cab67/ee/app/models/ci/minutes/usage.rb)
is a Value Object that provides [CI/CD minutes usage](../ci/pipelines/cicd_minutes.md)
for a given namespace.
#### Model class methods
These are class methods defined by _GitLab itself_, including the following
methods provided by Active Record:
@ -222,7 +242,7 @@ methods provided by Active Record:
Any other methods such as `find_by(some_column: X)` are not included, and
instead fall under the "Active Record" abstraction.
### Model instance methods
#### Model instance methods
Instance methods defined on Active Record models by _GitLab itself_. Methods
provided by Active Record are not included, except for the following methods:
@ -232,7 +252,7 @@ provided by Active Record are not included, except for the following methods:
- `destroy`
- `delete`
### Active Record
#### Active Record
The API provided by Active Record itself, such as the `where` method, `save`,
`delete_all`, and so on.

View File

@ -556,19 +556,6 @@ sudo -u git -H cp config/puma.rb.example config/puma.rb
# cores you have available. You can get that number via the `nproc` command.
sudo -u git -H editor config/puma.rb
# Disable 'git gc --auto' because GitLab already runs 'git gc' when needed
sudo -u git -H git config --global gc.auto 0
# Enable packfile bitmaps
sudo -u git -H git config --global repack.writeBitmaps true
# Enable push options
# Refer to https://docs.gitlab.com/ee/user/project/push_options.html for more information.
sudo -u git -H git config --global receive.advertisePushOptions true
# Enable fsyncObjectFiles to reduce risk of repository corruption if the server crashes
sudo -u git -H git config --global core.fsyncObjectFiles true
# Configure Redis connection settings
sudo -u git -H cp config/resque.yml.example config/resque.yml
sudo -u git -H cp config/cable.yml.example config/cable.yml

View File

@ -157,13 +157,29 @@ To fix this issue, you must disable SSL verification:
1. Change the global Git `sslVerify` option to `false` on the GitLab server.
- **For Omnibus installations**
- **For Omnibus installations in [GitLab 15.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6800) and later**:
```ruby
gitaly['gitconfig'] = [
{key: "http.sslVerify", value: "false"},
]
```
- **For Omnibus installations in GitLab 15.2 and earlier (legacy method)**:
```ruby
omnibus_gitconfig['system'] = { "http" => ["sslVerify = false"] }
```
- **For installations from source**
- **For installations from source in [GitLab 15.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6800) and later**, edit the Gitaly configuration (`gitaly.toml`):
```toml
[[git.config]]
key = "http.sslVerify"
value = "false"
```
- **For installations from source in GitLab 15.2 and earlier (legacy method)**:
```shell
git config --global http.sslVerify false

View File

@ -81,7 +81,15 @@ If you know the username, user ID, or email address, you can use the Rails conso
new_password = ::User.random_password
user.password = new_password
user.password_confirmation = new_password
```
```
To set a specific value for the new password:
```ruby
new_password = 'examplepassword'
user.password = new_password
user.password_confirmation = new_password
```
1. Optional. Notify the user that an administrator changed their password:

View File

@ -212,10 +212,10 @@ apply more than one:
[`gitlab.rb`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/13.5.1+ee.0/files/gitlab-config-template/gitlab.rb.template#L1435-1455) file:
```shell
omnibus_gitconfig['system'] = {
gitaly['gitconfig'] = [
# Set the http.postBuffer size, in bytes
"http" => ["postBuffer = 524288000"]
}
{key: "http.postBuffer", value: "524288000"},
]
```
1. After applying this change, apply the configuration change:

View File

@ -324,6 +324,15 @@ When transferring groups, note:
- Only explicit group membership is transferred, not inherited membership. If the group's owners have only inherited membership, this leaves the group without an owner. In this case, the user transferring the group becomes the group's owner.
- Transfers fail if [packages](../packages/index.md) exist in any of the projects in the group, or in any of its subgroups.
To transfer a group:
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Advanced** section.
1. In the **Remove group** section, select **Transfer group**.
1. Select the group name in the drop down menu.
1. Select **Transfer group**.
## Enable delayed project deletion **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) in GitLab 13.2.

View File

@ -1,77 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# A job to create ci_namespace_mirrors entries in batches
class BackfillCiNamespaceMirrors
class Namespace < ActiveRecord::Base # rubocop:disable Style/Documentation
include ::EachBatch
self.table_name = 'namespaces'
self.inheritance_column = nil
scope :base_query, -> do
select(:id, :parent_id)
end
end
PAUSE_SECONDS = 0.1
SUB_BATCH_SIZE = 500
def perform(start_id, end_id)
batch_query = Namespace.base_query.where(id: start_id..end_id)
batch_query.each_batch(of: SUB_BATCH_SIZE) do |sub_batch|
first, last = sub_batch.pick(Arel.sql('MIN(id), MAX(id)'))
ranged_query = Namespace.unscoped.base_query.where(id: first..last)
update_sql = <<~SQL
INSERT INTO ci_namespace_mirrors (namespace_id, traversal_ids)
#{insert_values(ranged_query)}
ON CONFLICT (namespace_id) DO NOTHING
SQL
# We do nothing on conflict because we consider they were already filled.
Namespace.connection.execute(update_sql)
sleep PAUSE_SECONDS
end
mark_job_as_succeeded(start_id, end_id)
end
private
def insert_values(batch)
calculated_traversal_ids(
batch.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336433')
)
end
# Copied from lib/gitlab/background_migration/backfill_namespace_traversal_ids_children.rb
def calculated_traversal_ids(batch)
<<~SQL
WITH RECURSIVE cte(source_id, namespace_id, parent_id, height) AS (
(
SELECT batch.id, batch.id, batch.parent_id, 1
FROM (#{batch.to_sql}) AS batch
)
UNION ALL
(
SELECT cte.source_id, n.id, n.parent_id, cte.height+1
FROM namespaces n, cte
WHERE n.id = cte.parent_id
)
)
SELECT flat_hierarchy.source_id as namespace_id,
array_agg(flat_hierarchy.namespace_id ORDER BY flat_hierarchy.height DESC) as traversal_ids
FROM (SELECT * FROM cte FOR UPDATE) flat_hierarchy
GROUP BY flat_hierarchy.source_id
SQL
end
def mark_job_as_succeeded(*arguments)
Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded('BackfillCiNamespaceMirrors', arguments)
end
end
end
end

View File

@ -1,52 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# A job to create ci_project_mirrors entries in batches
class BackfillCiProjectMirrors
class Project < ActiveRecord::Base # rubocop:disable Style/Documentation
include ::EachBatch
self.table_name = 'projects'
scope :base_query, -> do
select(:id, :namespace_id)
end
end
PAUSE_SECONDS = 0.1
SUB_BATCH_SIZE = 500
def perform(start_id, end_id)
batch_query = Project.base_query.where(id: start_id..end_id)
batch_query.each_batch(of: SUB_BATCH_SIZE) do |sub_batch|
first, last = sub_batch.pick(Arel.sql('MIN(id), MAX(id)'))
ranged_query = Project.unscoped.base_query.where(id: first..last)
update_sql = <<~SQL
INSERT INTO ci_project_mirrors (project_id, namespace_id)
#{insert_values(ranged_query)}
ON CONFLICT (project_id) DO NOTHING
SQL
# We do nothing on conflict because we consider they were already filled.
Project.connection.execute(update_sql)
sleep PAUSE_SECONDS
end
mark_job_as_succeeded(start_id, end_id)
end
private
def insert_values(batch)
batch.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336433').to_sql
end
def mark_job_as_succeeded(*arguments)
Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded('BackfillCiProjectMirrors', arguments)
end
end
end
end

View File

@ -1,13 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
class PopulateStatusColumnOfSecurityScans # rubocop:disable Style/Documentation
def perform(_start_id, _end_id)
# no-op
end
end
end
end
Gitlab::BackgroundMigration::PopulateStatusColumnOfSecurityScans.prepend_mod

View File

@ -39740,9 +39740,6 @@ msgstr ""
msgid "There was an error while fetching value stream analytics duration data."
msgstr ""
msgid "There was an error while fetching value stream summary data."
msgstr ""
msgid "There was an error with the reCAPTCHA. Please solve the reCAPTCHA again."
msgstr ""

View File

@ -11,7 +11,6 @@ import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filter
import { NOT_ENOUGH_DATA_ERROR } from '~/cycle_analytics/constants';
import initState from '~/cycle_analytics/store/state';
import {
permissions,
transformedProjectStagePathData,
selectedStage,
issueEvents,
@ -34,7 +33,6 @@ let wrapper;
const { id: groupId, path: groupPath } = currentGroup;
const defaultState = {
permissions,
currentGroup,
createdBefore,
createdAfter,
@ -240,24 +238,6 @@ describe('Value stream analytics component', () => {
});
});
describe('without enough permissions', () => {
beforeEach(() => {
wrapper = createComponent({
initialState: {
selectedStage,
permissions: {
...permissions,
[selectedStage.id]: false,
},
},
});
});
it('renders the empty stage with `You need permission.` message', () => {
expect(findEmptyStageTitle()).toBe('You need permission.');
});
});
describe('without a selected stage', () => {
beforeEach(() => {
wrapper = createComponent({

View File

@ -101,30 +101,12 @@ export const selectedStage = {
...issueStage,
value: null,
active: false,
isUserAllowed: true,
emptyStageText:
'The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.',
slug: 'issue',
};
export const stats = [issueStage, planStage, codeStage, testStage, reviewStage, stagingStage];
export const permissions = {
issue: true,
plan: true,
code: true,
test: true,
review: true,
staging: true,
};
export const rawData = {
summary,
stats,
permissions,
};
export const convertedData = {
summary: [
{ value: '20', title: 'New Issues' },

View File

@ -153,6 +153,19 @@ describe('Project Value Stream Analytics actions', () => {
});
});
});
describe('with no value stream stages available', () => {
it('will return SET_NO_ACCESS_ERROR', () => {
state = { ...state, stages: [] };
testAction({
action: actions.setInitialStage,
state,
payload: null,
expectedMutations: [{ type: 'SET_NO_ACCESS_ERROR' }],
expectedActions: [],
});
});
});
});
describe('updateStageTablePagination', () => {
@ -170,46 +183,6 @@ describe('Project Value Stream Analytics actions', () => {
});
});
describe('fetchCycleAnalyticsData', () => {
beforeEach(() => {
state = { ...defaultState, endpoints: mockEndpoints };
mock = new MockAdapter(axios);
mock.onGet(mockRequestPath).reply(httpStatusCodes.OK);
});
it(`dispatches the 'setSelectedStage' and 'fetchStageData' actions`, () =>
testAction({
action: actions.fetchCycleAnalyticsData,
state,
payload: {},
expectedMutations: [
{ type: 'REQUEST_CYCLE_ANALYTICS_DATA' },
{ type: 'RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS' },
],
expectedActions: [],
}));
describe('with a failing request', () => {
beforeEach(() => {
state = { endpoints: mockEndpoints };
mock = new MockAdapter(axios);
mock.onGet(mockRequestPath).reply(httpStatusCodes.BAD_REQUEST);
});
it(`commits the 'RECEIVE_CYCLE_ANALYTICS_DATA_ERROR' mutation`, () =>
testAction({
action: actions.fetchCycleAnalyticsData,
state,
payload: {},
expectedMutations: [
{ type: 'REQUEST_CYCLE_ANALYTICS_DATA' },
{ type: 'RECEIVE_CYCLE_ANALYTICS_DATA_ERROR' },
],
expectedActions: [],
}));
});
});
describe('fetchStageData', () => {
const mockStagePath = /value_streams\/\w+\/stages\/\w+\/records/;
const headers = {
@ -529,14 +502,13 @@ describe('Project Value Stream Analytics actions', () => {
});
describe('fetchValueStreamStageData', () => {
it('will dispatch the fetchCycleAnalyticsData, fetchStageData, fetchStageMedians and fetchStageCountValues actions', () =>
it('will dispatch the fetchStageData, fetchStageMedians and fetchStageCountValues actions', () =>
testAction({
action: actions.fetchValueStreamStageData,
state,
payload: {},
expectedMutations: [],
expectedActions: [
{ type: 'fetchCycleAnalyticsData' },
{ type: 'fetchStageData' },
{ type: 'fetchStageMedians' },
{ type: 'fetchStageCountValues' },

View File

@ -38,31 +38,24 @@ describe('Project Value Stream Analytics mutations', () => {
});
it.each`
mutation | stateKey | value
${types.REQUEST_VALUE_STREAMS} | ${'valueStreams'} | ${[]}
${types.RECEIVE_VALUE_STREAMS_ERROR} | ${'valueStreams'} | ${[]}
${types.REQUEST_VALUE_STREAM_STAGES} | ${'stages'} | ${[]}
${types.RECEIVE_VALUE_STREAM_STAGES_ERROR} | ${'stages'} | ${[]}
${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${'isLoading'} | ${true}
${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${'hasError'} | ${false}
${types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS} | ${'hasError'} | ${false}
${types.RECEIVE_CYCLE_ANALYTICS_DATA_ERROR} | ${'isLoading'} | ${false}
${types.RECEIVE_CYCLE_ANALYTICS_DATA_ERROR} | ${'hasError'} | ${true}
${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true}
${types.REQUEST_STAGE_DATA} | ${'isEmptyStage'} | ${false}
${types.REQUEST_STAGE_DATA} | ${'hasError'} | ${false}
${types.REQUEST_STAGE_DATA} | ${'selectedStageEvents'} | ${[]}
${types.RECEIVE_STAGE_DATA_SUCCESS} | ${'isLoadingStage'} | ${false}
${types.RECEIVE_STAGE_DATA_SUCCESS} | ${'selectedStageEvents'} | ${[]}
${types.RECEIVE_STAGE_DATA_SUCCESS} | ${'hasError'} | ${false}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'selectedStageEvents'} | ${[]}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'hasError'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true}
${types.REQUEST_STAGE_MEDIANS} | ${'medians'} | ${{}}
${types.RECEIVE_STAGE_MEDIANS_ERROR} | ${'medians'} | ${{}}
${types.REQUEST_STAGE_COUNTS} | ${'stageCounts'} | ${{}}
${types.RECEIVE_STAGE_COUNTS_ERROR} | ${'stageCounts'} | ${{}}
mutation | stateKey | value
${types.REQUEST_VALUE_STREAMS} | ${'valueStreams'} | ${[]}
${types.RECEIVE_VALUE_STREAMS_ERROR} | ${'valueStreams'} | ${[]}
${types.REQUEST_VALUE_STREAM_STAGES} | ${'stages'} | ${[]}
${types.RECEIVE_VALUE_STREAM_STAGES_ERROR} | ${'stages'} | ${[]}
${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true}
${types.REQUEST_STAGE_DATA} | ${'isEmptyStage'} | ${false}
${types.REQUEST_STAGE_DATA} | ${'selectedStageEvents'} | ${[]}
${types.RECEIVE_STAGE_DATA_SUCCESS} | ${'isLoadingStage'} | ${false}
${types.RECEIVE_STAGE_DATA_SUCCESS} | ${'selectedStageEvents'} | ${[]}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'selectedStageEvents'} | ${[]}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true}
${types.REQUEST_STAGE_MEDIANS} | ${'medians'} | ${{}}
${types.RECEIVE_STAGE_MEDIANS_ERROR} | ${'medians'} | ${{}}
${types.REQUEST_STAGE_COUNTS} | ${'stageCounts'} | ${{}}
${types.RECEIVE_STAGE_COUNTS_ERROR} | ${'stageCounts'} | ${{}}
${types.SET_NO_ACCESS_ERROR} | ${'hasNoAccessError'} | ${true}
`('$mutation will set $stateKey to $value', ({ mutation, stateKey, value }) => {
mutations[mutation](state);

View File

@ -1,46 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillCiNamespaceMirrors, :migration,
:suppress_gitlab_schemas_validate_connection, schema: 20211208122200 do
let(:namespaces) { table(:namespaces) }
let(:ci_namespace_mirrors) { table(:ci_namespace_mirrors) }
subject { described_class.new }
describe '#perform' do
it 'creates hierarchies for all namespaces in range' do
namespaces.create!(id: 5, name: 'test1', path: 'test1')
namespaces.create!(id: 7, name: 'test2', path: 'test2')
namespaces.create!(id: 8, name: 'test3', path: 'test3')
subject.perform(5, 7)
expect(ci_namespace_mirrors.all).to contain_exactly(
an_object_having_attributes(namespace_id: 5, traversal_ids: [5]),
an_object_having_attributes(namespace_id: 7, traversal_ids: [7])
)
end
it 'handles existing hierarchies gracefully' do
namespaces.create!(id: 5, name: 'test1', path: 'test1')
test2 = namespaces.create!(id: 7, name: 'test2', path: 'test2')
namespaces.create!(id: 8, name: 'test3', path: 'test3', parent_id: 7)
namespaces.create!(id: 9, name: 'test4', path: 'test4')
# Simulate a situation where a user has had a chance to move a group to another parent
# before the background migration has had a chance to run
test2.update!(parent_id: 5)
ci_namespace_mirrors.create!(namespace_id: test2.id, traversal_ids: [5, 7])
subject.perform(5, 8)
expect(ci_namespace_mirrors.all).to contain_exactly(
an_object_having_attributes(namespace_id: 5, traversal_ids: [5]),
an_object_having_attributes(namespace_id: 7, traversal_ids: [5, 7]),
an_object_having_attributes(namespace_id: 8, traversal_ids: [5, 7, 8])
)
end
end
end

View File

@ -1,47 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillCiProjectMirrors, :migration,
:suppress_gitlab_schemas_validate_connection, schema: 20211208122201 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:ci_project_mirrors) { table(:ci_project_mirrors) }
subject { described_class.new }
describe '#perform' do
it 'creates ci_project_mirrors for all projects in range' do
namespaces.create!(id: 10, name: 'namespace1', path: 'namespace1')
projects.create!(id: 5, namespace_id: 10, name: 'test1', path: 'test1')
projects.create!(id: 7, namespace_id: 10, name: 'test2', path: 'test2')
projects.create!(id: 8, namespace_id: 10, name: 'test3', path: 'test3')
subject.perform(5, 7)
expect(ci_project_mirrors.all).to contain_exactly(
an_object_having_attributes(project_id: 5, namespace_id: 10),
an_object_having_attributes(project_id: 7, namespace_id: 10)
)
end
it 'handles existing ci_project_mirrors gracefully' do
namespaces.create!(id: 10, name: 'namespace1', path: 'namespace1')
namespaces.create!(id: 11, name: 'namespace2', path: 'namespace2', parent_id: 10)
projects.create!(id: 5, namespace_id: 10, name: 'test1', path: 'test1')
projects.create!(id: 7, namespace_id: 11, name: 'test2', path: 'test2')
projects.create!(id: 8, namespace_id: 11, name: 'test3', path: 'test3')
# Simulate a situation where a user has had a chance to move a project to another namespace
# before the background migration has had a chance to run
ci_project_mirrors.create!(project_id: 7, namespace_id: 10)
subject.perform(5, 7)
expect(ci_project_mirrors.all).to contain_exactly(
an_object_having_attributes(project_id: 5, namespace_id: 10),
an_object_having_attributes(project_id: 7, namespace_id: 10)
)
end
end
end

View File

@ -1,48 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe SchedulePopulateStatusColumnOfSecurityScans, :suppress_gitlab_schemas_validate_connection do
before do
allow(Gitlab).to receive(:ee?).and_return(ee?)
stub_const("#{described_class.name}::BATCH_SIZE", 1)
end
context 'when the Gitlab instance is CE' do
let(:ee?) { false }
it 'does not run the migration' do
expect { migrate! }.not_to change { BackgroundMigrationWorker.jobs.size }
end
end
context 'when the Gitlab instance is EE' do
let(:ee?) { true }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:builds) { table(:ci_builds) }
let(:security_scans) { table(:security_scans) }
let(:namespace) { namespaces.create!(name: "foo", path: "bar") }
let(:project) { projects.create!(namespace_id: namespace.id) }
let(:pipeline) { pipelines.create!(project_id: project.id, ref: 'master', sha: 'adf43c3a', status: 'success') }
let(:ci_build) { builds.create!(commit_id: pipeline.id, retried: false, type: 'Ci::Build') }
let!(:security_scan_1) { security_scans.create!(build_id: ci_build.id, scan_type: 1) }
let!(:security_scan_2) { security_scans.create!(build_id: ci_build.id, scan_type: 2) }
around do |example|
freeze_time { Sidekiq::Testing.fake! { example.run } }
end
it 'schedules the background jobs', :aggregate_failures do
migrate!
expect(BackgroundMigrationWorker.jobs.size).to be(2)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, security_scan_1.id, security_scan_1.id)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, security_scan_2.id, security_scan_2.id)
end
end
end

View File

@ -1 +1 @@
- "./spec/migrations/20210907211557_finalize_ci_builds_bigint_conversion_spec.rb"
[]