Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
672f729cf2
commit
f2d662be68
|
|
@ -6,7 +6,7 @@ workflow:
|
|||
|
||||
include:
|
||||
- project: gitlab-org/quality/pipeline-common
|
||||
ref: 5.1.1
|
||||
ref: 5.2.1
|
||||
file:
|
||||
- /ci/base.gitlab-ci.yml
|
||||
- /ci/allure-report.yml
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ variables:
|
|||
FF_NETWORK_PER_BUILD: 1
|
||||
GDK_URL: http://gdk.test:3000
|
||||
before_script:
|
||||
- echo "SUITE_RAN=true" > suite_status.env
|
||||
- echo -e "\e[0Ksection_start:`date +%s`:pull_image\r\e[0KPull GDK QA image"
|
||||
- docker pull ${GDK_IMAGE}
|
||||
- echo -e "\e[0Ksection_end:`date +%s`:pull_image\r\e[0K"
|
||||
|
|
@ -55,7 +56,6 @@ variables:
|
|||
- cd qa && bundle install
|
||||
- retry_exponential test_url ${GDK_URL}/users/sign_in
|
||||
- echo -e "\e[0Ksection_end:`date +%s`:launch_gdk\r\e[0K"
|
||||
- echo "SUITE_RAN=true" > suite_status.env
|
||||
script:
|
||||
- echo -e "\e[0Ksection_start:`date +%s`:run_tests\r\e[0KRun E2E tests"
|
||||
- QA_COMMAND="bundle exec bin/qa Test::Instance::All ${GDK_URL} -- ${RSPEC_TAGS} ${RSPEC_REPORT_OPTS}"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export default {
|
|||
});
|
||||
this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } });
|
||||
}
|
||||
if (this.designCollection.copyState === 'ERROR') {
|
||||
if (this.designCollection?.copyState === 'ERROR') {
|
||||
createAlert({
|
||||
message: s__(
|
||||
'DesignManagement|There was an error moving your designs. Please upload your designs below.',
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ import {
|
|||
} from '../utils/error_messages';
|
||||
import { trackDesignCreate, trackDesignUpdate } from '../utils/tracking';
|
||||
|
||||
export const i18n = {
|
||||
dropzoneDescriptionText: __('Drag your designs here or %{linkStart}click to upload%{linkEnd}.'),
|
||||
designLoadingError: __('An error occurred while loading designs. Please try again.'),
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlLoadingIcon,
|
||||
|
|
@ -346,9 +351,7 @@ export default {
|
|||
animation: 200,
|
||||
ghostClass: 'gl-visibility-hidden',
|
||||
},
|
||||
i18n: {
|
||||
dropzoneDescriptionText: __('Drag your designs here or %{linkStart}click to upload%{linkEnd}.'),
|
||||
},
|
||||
i18n,
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -427,7 +430,7 @@ export default {
|
|||
<div :class="designContentWrapperClass">
|
||||
<gl-loading-icon v-if="isLoading" size="lg" />
|
||||
<gl-alert v-else-if="error" variant="danger" :dismissible="false">
|
||||
{{ __('An error occurred while loading designs. Please try again.') }}
|
||||
{{ $options.i18n.designLoadingError }}
|
||||
</gl-alert>
|
||||
<header
|
||||
v-else-if="isDesignCollectionCopying"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ query projectUsersSearch($search: String!, $fullPath: ID!, $after: String, $firs
|
|||
id
|
||||
users: projectMembers(
|
||||
search: $search
|
||||
relations: [DIRECT, INHERITED, INVITED_GROUPS]
|
||||
relations: [DIRECT, INHERITED, INVITED_GROUPS, SHARED_INTO_ANCESTORS]
|
||||
first: $first
|
||||
after: $after
|
||||
sort: USER_FULL_NAME_ASC
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ query searchUsers($fullPath: ID!, $search: String, $isProject: Boolean = false)
|
|||
}
|
||||
project(fullPath: $fullPath) @include(if: $isProject) {
|
||||
id
|
||||
projectMembers(search: $search, relations: [DIRECT, INHERITED, INVITED_GROUPS]) {
|
||||
projectMembers(
|
||||
search: $search
|
||||
relations: [DIRECT, INHERITED, INVITED_GROUPS, SHARED_INTO_ANCESTORS]
|
||||
) {
|
||||
nodes {
|
||||
id
|
||||
user {
|
||||
|
|
|
|||
|
|
@ -688,21 +688,6 @@ export const getCookie = (name) => Cookies.get(name);
|
|||
|
||||
export const removeCookie = (name) => Cookies.remove(name);
|
||||
|
||||
/**
|
||||
* Returns the status of a feature flag.
|
||||
* Currently, there is no way to access feature
|
||||
* flags in Vuex other than directly tapping into
|
||||
* window.gon.
|
||||
*
|
||||
* This should only be used on Vuex. If feature flags
|
||||
* need to be accessed in Vue components consider
|
||||
* using the Vue feature flag mixin.
|
||||
*
|
||||
* @param {String} flag Feature flag
|
||||
* @returns {Boolean} on/off
|
||||
*/
|
||||
export const isFeatureFlagEnabled = (flag) => window.gon.features?.[flag];
|
||||
|
||||
/**
|
||||
* This method takes in array with snake_case strings
|
||||
* and returns a new array with camelCase strings
|
||||
|
|
|
|||
|
|
@ -1,27 +1,14 @@
|
|||
<script>
|
||||
import { GlButton, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import { GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import EMPTY_STATE_SVG_URL from '@gitlab/svgs/dist/illustrations/empty-state/empty-merge-requests-md.svg?url';
|
||||
import api from '~/api';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
|
||||
export default {
|
||||
name: 'MRWidgetNothingToMerge',
|
||||
components: {
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlLink,
|
||||
},
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClickNewFile() {
|
||||
api.trackRedisHllUserEvent('i_code_review_widget_nothing_merge_click_new_file');
|
||||
},
|
||||
},
|
||||
ciHelpPage: helpPagePath('ci/quick_start/index.html'),
|
||||
EMPTY_STATE_SVG_URL,
|
||||
};
|
||||
|
|
@ -31,42 +18,30 @@ export default {
|
|||
<div class="mr-widget-body mr-widget-empty-state">
|
||||
<div class="row">
|
||||
<div
|
||||
class="col-md-3 col-12 text-center d-flex justify-content-center align-items-center svg-content svg-150 pb-0 pt-0"
|
||||
class="col-md-3 col-12 text-center d-flex justify-content-center align-items-center svg-content svg-130 pb-0 pt-0"
|
||||
>
|
||||
<img
|
||||
:alt="s__('mrWidgetNothingToMerge|This merge request contains no changes.')"
|
||||
:src="$options.EMPTY_STATE_SVG_URL"
|
||||
/>
|
||||
<img :src="$options.EMPTY_STATE_SVG_URL" :alt="''" />
|
||||
</div>
|
||||
<div class="text col-md-9 col-12">
|
||||
<p class="highlight">
|
||||
{{ s__('mrWidgetNothingToMerge|This merge request contains no changes.') }}
|
||||
<p class="highlight mt-3">
|
||||
{{ s__('mrWidgetNothingToMerge|Merge request contains no changes') }}
|
||||
</p>
|
||||
<p data-testid="nothing-to-merge-body">
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, push a commit or edit this merge request to use a different branch. With %{linkStart}CI/CD%{linkEnd}, automatically test your changes before merging.',
|
||||
'mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, use the %{boldStart}Code%{boldEnd} dropdown list above, then test them with %{linkStart}CI/CD%{linkEnd} before merging.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #bold="{ content }">
|
||||
<b>{{ content }}</b>
|
||||
</template>
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="$options.ciHelpPage" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
<div>
|
||||
<gl-button
|
||||
v-if="mr.newBlobPath"
|
||||
:href="mr.newBlobPath"
|
||||
category="primary"
|
||||
variant="confirm"
|
||||
data-testid="createFileButton"
|
||||
@click="onClickNewFile"
|
||||
>
|
||||
{{ __('Create file') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ module PreferencesHelper
|
|||
[
|
||||
[s_('ProjectView|Files and Readme (default)'), :files],
|
||||
[s_('ProjectView|Activity'), :activity],
|
||||
[s_('ProjectView|Readme'), :readme]
|
||||
[s_('ProjectView|Readme'), :readme],
|
||||
[s_('ProjectView|Wiki'), :wiki]
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ class NamespaceSetting < ApplicationRecord
|
|||
|
||||
before_validation :normalize_default_branch_name
|
||||
|
||||
after_create :set_code_suggestions_default
|
||||
|
||||
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
|
||||
chronic_duration_attr :subgroup_runner_token_expiration_interval_human_readable, :subgroup_runner_token_expiration_interval
|
||||
chronic_duration_attr :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval
|
||||
|
|
@ -87,6 +89,14 @@ class NamespaceSetting < ApplicationRecord
|
|||
self.default_branch_name = default_branch_name.presence
|
||||
end
|
||||
|
||||
def set_code_suggestions_default
|
||||
# users should have code suggestions disabled by default
|
||||
return if namespace&.user_namespace?
|
||||
|
||||
# groups should have code suggestions enabled by default
|
||||
update_column(:code_suggestions, true)
|
||||
end
|
||||
|
||||
def allow_mfa_for_group
|
||||
if namespace&.subgroup? && allow_mfa_for_subgroups == false
|
||||
errors.add(:allow_mfa_for_subgroups, _('is not allowed since the group is not top-level group.'))
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ class User < ApplicationRecord
|
|||
enum dashboard: { projects: 0, stars: 1, your_activity: 10, project_activity: 2, starred_project_activity: 3, groups: 4, todos: 5, issues: 6, merge_requests: 7, operations: 8, followed_user_activity: 9 }
|
||||
|
||||
# User's Project preference
|
||||
enum project_view: { readme: 0, activity: 1, files: 2 }
|
||||
enum project_view: { readme: 0, activity: 1, files: 2, wiki: 3 }
|
||||
|
||||
# User's role
|
||||
enum role: { software_developer: 0, development_team_lead: 1, devops_engineer: 2, systems_administrator: 3, security_analyst: 4, data_analyst: 5, product_manager: 6, product_designer: 7, other: 8 }, _suffix: true
|
||||
|
|
|
|||
|
|
@ -35,6 +35,15 @@ DB_MIGRATION_TESTING_REQUIRED_MESSAGE = <<~MSG
|
|||
requesting review to test your migrations against production data.
|
||||
MSG
|
||||
|
||||
DB_OLD_MIGRATIONS_MESSAGE = <<~MSG
|
||||
⌛ **Migration Timestamp Out of Date**
|
||||
The following migrations have timestamps that are over three weeks old:
|
||||
|
||||
%<old_migrations>s
|
||||
|
||||
Please double check the timestamps and update them if possible. [Why does this matter?](https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-timestamp-age)
|
||||
MSG
|
||||
|
||||
DATABASE_APPROVED_LABEL = 'database::approved'
|
||||
|
||||
non_geo_db_schema_updated = !git.modified_files.grep(%r{\Adb/structure\.sql}).empty?
|
||||
|
|
@ -77,3 +86,11 @@ if helper.mr_labels.include?('database') || db_paths_to_review.any?
|
|||
helper.labels_to_add << 'database::review pending'
|
||||
end
|
||||
end
|
||||
|
||||
cutoff = Date.today - 21 # Three weeks ago
|
||||
|
||||
old_migrations = database.find_migration_files_before(git.added_files, cutoff)
|
||||
|
||||
if old_migrations.present?
|
||||
warn format(DB_OLD_MIGRATIONS_MESSAGE, old_migrations: old_migrations.map { |m| "* #{m}" }.join("\n"))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../tooling/danger/database'
|
||||
|
||||
module Danger
|
||||
class Database < ::Danger::Plugin
|
||||
# Put the helper code somewhere it can be tested
|
||||
include Tooling::Danger::Database
|
||||
end
|
||||
end
|
||||
|
|
@ -48,3 +48,13 @@ by the server responses that are returned. You can create new responses by editi
|
|||
and then select **Execute** once again.
|
||||
|
||||

|
||||
|
||||
## Vision
|
||||
|
||||
The API code is the single source of truth, and the API documentation should be tightly coupled to its implementation. The OpenAPI specification provides a standardized and comprehensive way to document APIs. It should be the go-to format for documenting the GitLab REST API. This will result in more accurate, reliable, and user-friendly documentation that enhances the overall experience of using the GitLab REST API.
|
||||
|
||||
To achieve this it should be a requirement to update the OpenAPI specification with every API code change. By doing so, we ensure that the documentation is always up-to-date and accurate, reducing the risk of confusion as well as errors for our users.
|
||||
|
||||
The OpenAPI documentation should be autogenerated from the API code, so that it is easy to keep it up to date and accurate. This will save time and effort for our documentation team.
|
||||
|
||||
You can follow the current progress of this vision in the [Document the REST API in OpenAPI V2 epic](https://gitlab.com/groups/gitlab-org/-/epics/8926).
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ listed in the descriptions of the relevant settings.
|
|||
| `max_export_size` | integer | no | Maximum export size in MB. 0 for unlimited. Default = 0 (unlimited). |
|
||||
| `max_import_size` | integer | no | Maximum import size in MB. 0 for unlimited. Default = 0 (unlimited). [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/251106) from 50 MB to 0 in GitLab 13.8. |
|
||||
| `max_pages_size` | integer | no | Maximum size of pages repositories in MB. |
|
||||
| `max_personal_access_token_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for access tokens in days. |
|
||||
| `max_personal_access_token_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for access tokens in days. When left blank, default value of 365 is applied. When set, value must be 365 or less. When changed, existing access tokens with an expiration date beyond the maximum allowable lifetime are revoked.|
|
||||
| `max_ssh_key_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for SSH keys in days. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1007) in GitLab 14.6. |
|
||||
| `max_terraform_state_size_bytes` | integer | no | Maximum size in bytes of the [Terraform state](../administration/terraform_state.md) files. Set this to 0 for unlimited file size. |
|
||||
| `metrics_method_call_threshold` | integer | no | A method call is only tracked when it takes longer than the given amount of milliseconds. |
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ With this configuration, GitLab adds **artifact 1** as a link to `file.txt` to t
|
|||
|
||||
By default artifacts are always kept for successful pipelines for the most recent commit on
|
||||
each ref. This means that the latest artifacts do not immediately expire according
|
||||
to the `expire_in` specification.
|
||||
to the `expire_in` configuration.
|
||||
|
||||
If a pipeline for a new commit on the same ref completes successfully, the previous pipeline's
|
||||
artifacts are deleted according to the `expire_in` configuration. The artifacts
|
||||
|
|
@ -350,6 +350,10 @@ a project, you can disable this behavior to save space:
|
|||
1. Expand **Artifacts**.
|
||||
1. Clear the **Keep artifacts from most recent successful jobs** checkbox.
|
||||
|
||||
After disabling this setting, all new artifacts expire according to the `expire_in` configuration.
|
||||
Artifacts in old pipelines continue to be kept until a new pipeline runs for the same ref.
|
||||
Then the artifacts in the earlier pipeline for that ref are allowed to expire too.
|
||||
|
||||
You can disable this behavior for all projects on a self-managed instance in the
|
||||
[instance's CI/CD settings](../../user/admin_area/settings/continuous_integration.md#keep-the-latest-artifacts-for-all-jobs-in-the-latest-successful-pipelines).
|
||||
|
||||
|
|
|
|||
|
|
@ -168,9 +168,7 @@ When you use merge request pipelines, you can use:
|
|||
- All the same [predefined variables](../variables/predefined_variables.md) that are
|
||||
available in branch pipelines.
|
||||
- [Additional predefined variables](../variables/predefined_variables.md#predefined-variables-for-merge-request-pipelines)
|
||||
available only to jobs in merge request pipelines. These variables contain
|
||||
information from the associated merge request, which can be when calling the
|
||||
[GitLab Merge Request API endpoint](../../api/merge_requests.md) from a job.
|
||||
available only to jobs in merge request pipelines.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
|||
|
|
@ -35950,6 +35950,9 @@ msgstr ""
|
|||
msgid "ProjectView|Readme"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectView|Wiki"
|
||||
msgstr ""
|
||||
|
||||
msgid "Projects"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -50651,10 +50654,10 @@ msgstr ""
|
|||
msgid "When enabled, cleanup policies execute faster but put more load on Redis."
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, existing access tokens may be revoked. Leave blank for no limit."
|
||||
msgid "When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces."
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces."
|
||||
msgid "When left blank, default value of 365 is applied. When set, value must be 365 or less. When changed, existing access tokens with an expiration date beyond the maximum allowable lifetime are revoked."
|
||||
msgstr ""
|
||||
|
||||
msgid "When merge requests and commits in the default branch close, any issues they reference also close."
|
||||
|
|
@ -53788,10 +53791,10 @@ msgstr ""
|
|||
msgid "mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}."
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidgetNothingToMerge|This merge request contains no changes."
|
||||
msgid "mrWidgetNothingToMerge|Merge request contains no changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, push a commit or edit this merge request to use a different branch. With %{linkStart}CI/CD%{linkEnd}, automatically test your changes before merging."
|
||||
msgid "mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, use the %{boldStart}Code%{boldEnd} dropdown list above, then test them with %{linkStart}CI/CD%{linkEnd} before merging."
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ RSpec.describe 'Dropdown assignee', :js, feature_category: :team_planning do
|
|||
expect(page).to have_text group_user.name
|
||||
expect(page).to have_text subgroup_user.name
|
||||
expect(page).to have_text invited_to_project_group_user.name
|
||||
expect(page).to have_text invited_to_group_group_user.name
|
||||
expect(page).not_to have_text subsubgroup_user.name
|
||||
expect(page).not_to have_text invited_to_group_group_user.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Design management index page designs renders error 1`] = `
|
||||
<div
|
||||
class="gl-mt-4"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<div
|
||||
class="gl-bg-gray-10 gl-border gl-border-t-0 gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-px-5"
|
||||
>
|
||||
<gl-alert-stub
|
||||
dismisslabel="Dismiss"
|
||||
primarybuttonlink=""
|
||||
primarybuttontext=""
|
||||
secondarybuttonlink=""
|
||||
secondarybuttontext=""
|
||||
showicon="true"
|
||||
title=""
|
||||
variant="danger"
|
||||
>
|
||||
|
||||
An error occurred while loading designs. Please try again.
|
||||
|
||||
</gl-alert-stub>
|
||||
</div>
|
||||
|
||||
<router-view-stub
|
||||
name="default"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Design management index page designs renders loading icon 1`] = `
|
||||
<div
|
||||
class="gl-mt-4"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<div
|
||||
class="gl-bg-gray-10 gl-border gl-border-t-0 gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-px-5"
|
||||
>
|
||||
<gl-loading-icon-stub
|
||||
color="dark"
|
||||
label="Loading"
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<router-view-stub
|
||||
name="default"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlEmptyState } from '@gitlab/ui';
|
||||
import { GlEmptyState, GlLoadingIcon, GlAlert } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
||||
import VueApollo, { ApolloMutation } from 'vue-apollo';
|
||||
|
|
@ -16,7 +16,7 @@ import DesignDestroyer from '~/design_management/components/design_destroyer.vue
|
|||
import Design from '~/design_management/components/list/item.vue';
|
||||
import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql';
|
||||
import uploadDesignMutation from '~/design_management/graphql/mutations/upload_design.mutation.graphql';
|
||||
import Index from '~/design_management/pages/index.vue';
|
||||
import Index, { i18n } from '~/design_management/pages/index.vue';
|
||||
import createRouter from '~/design_management/router';
|
||||
import { DESIGNS_ROUTE_NAME } from '~/design_management/router/constants';
|
||||
import * as utils from '~/design_management/utils/design_management_utils';
|
||||
|
|
@ -117,6 +117,8 @@ describe('Design management index page', () => {
|
|||
const findDesignUploadButton = () => wrapper.findByTestId('design-upload-button');
|
||||
const findDesignToolbarWrapper = () => wrapper.findByTestId('design-toolbar-wrapper');
|
||||
const findDesignUpdateAlert = () => wrapper.findByTestId('design-update-alert');
|
||||
const findLoadinIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
|
||||
async function moveDesigns(localWrapper) {
|
||||
await waitForPromises();
|
||||
|
|
@ -177,13 +179,14 @@ describe('Design management index page', () => {
|
|||
function createComponentWithApollo({
|
||||
permissionsHandler = jest.fn().mockResolvedValue(getPermissionsQueryResponse()),
|
||||
moveHandler = jest.fn().mockResolvedValue(moveDesignMutationResponse),
|
||||
getDesignListHandler = jest.fn().mockResolvedValue(getDesignListQueryResponse()),
|
||||
}) {
|
||||
Vue.use(VueApollo);
|
||||
permissionsQueryHandler = permissionsHandler;
|
||||
moveDesignHandler = moveHandler;
|
||||
|
||||
const requestHandlers = [
|
||||
[getDesignListQuery, jest.fn().mockResolvedValue(getDesignListQueryResponse())],
|
||||
[getDesignListQuery, getDesignListHandler],
|
||||
[permissionsQuery, permissionsQueryHandler],
|
||||
[moveDesignMutation, moveDesignHandler],
|
||||
];
|
||||
|
|
@ -203,24 +206,12 @@ describe('Design management index page', () => {
|
|||
describe('designs', () => {
|
||||
it('renders loading icon', () => {
|
||||
createComponent({ loading: true });
|
||||
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders error', async () => {
|
||||
createComponent();
|
||||
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ error: true });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
expect(findLoadinIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders a toolbar with buttons when there are designs', () => {
|
||||
createComponent({ allVersions: [mockVersion] });
|
||||
|
||||
expect(findLoadinIcon().exists()).toBe(false);
|
||||
expect(findToolbar().exists()).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -382,9 +373,8 @@ describe('Design management index page', () => {
|
|||
|
||||
it('updates state appropriately after upload complete', async () => {
|
||||
createComponent({ stubs: { GlEmptyState } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
|
||||
const designDropzone = findFirstDropzoneWithDesign();
|
||||
designDropzone.vm.$emit('change', 'test');
|
||||
|
||||
wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
|
||||
await nextTick();
|
||||
|
|
@ -396,10 +386,8 @@ describe('Design management index page', () => {
|
|||
|
||||
it('updates state appropriately after upload error', async () => {
|
||||
createComponent({ stubs: { GlEmptyState } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
|
||||
|
||||
const designDropzone = findFirstDropzoneWithDesign();
|
||||
designDropzone.vm.$emit('change', 'test');
|
||||
wrapper.vm.onUploadDesignError();
|
||||
await nextTick();
|
||||
expect(wrapper.vm.filesToBeSaved).toEqual([]);
|
||||
|
|
@ -752,6 +740,16 @@ describe('Design management index page', () => {
|
|||
});
|
||||
|
||||
describe('with mocked Apollo client', () => {
|
||||
it('renders error', async () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error = jest.fn();
|
||||
|
||||
createComponentWithApollo({
|
||||
getDesignListHandler: jest.fn().mockRejectedValue(new Error('GraphQL error')),
|
||||
});
|
||||
await waitForPromises();
|
||||
expect(findAlert().text()).toBe(i18n.designLoadingError);
|
||||
});
|
||||
it('has a design with id 1 as a first one', async () => {
|
||||
createComponentWithApollo({});
|
||||
await waitForPromises();
|
||||
|
|
|
|||
|
|
@ -4,26 +4,15 @@ import NothingToMerge from '~/vue_merge_request_widget/components/states/nothing
|
|||
|
||||
describe('NothingToMerge', () => {
|
||||
let wrapper;
|
||||
const newBlobPath = '/foo';
|
||||
|
||||
const defaultProps = {
|
||||
mr: {
|
||||
newBlobPath,
|
||||
},
|
||||
};
|
||||
|
||||
const createComponent = (props = defaultProps) => {
|
||||
const createComponent = () => {
|
||||
wrapper = shallowMountExtended(NothingToMerge, {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
stubs: {
|
||||
GlSprintf,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findCreateButton = () => wrapper.findByTestId('createFileButton');
|
||||
const findNothingToMergeTextBody = () => wrapper.findByTestId('nothing-to-merge-body');
|
||||
|
||||
describe('With Blob link', () => {
|
||||
|
|
@ -32,27 +21,10 @@ describe('NothingToMerge', () => {
|
|||
});
|
||||
|
||||
it('shows the component with the correct text and highlights', () => {
|
||||
expect(wrapper.text()).toContain('This merge request contains no changes.');
|
||||
expect(wrapper.text()).toContain('Merge request contains no changes');
|
||||
expect(findNothingToMergeTextBody().text()).toContain(
|
||||
'Use merge requests to propose changes to your project and discuss them with your team. To make changes, push a commit or edit this merge request to use a different branch.',
|
||||
'Use merge requests to propose changes to your project and discuss them with your team. To make changes, use the Code dropdown list above, then test them with CI/CD before merging.',
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the Create file button with the correct attributes', () => {
|
||||
const createButton = findCreateButton();
|
||||
|
||||
expect(createButton.exists()).toBe(true);
|
||||
expect(createButton.attributes('href')).toBe(newBlobPath);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Without Blob link', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ mr: { newBlobPath: '' } });
|
||||
});
|
||||
|
||||
it('does not show the Create file button', () => {
|
||||
expect(findCreateButton().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,6 +54,36 @@ RSpec.describe NamespaceSetting, feature_category: :subgroups, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#code_suggestions' do
|
||||
context 'when group namespaces' do
|
||||
let(:settings) { group.namespace_settings }
|
||||
let(:group) { create(:group) }
|
||||
|
||||
context 'when group is created' do
|
||||
it 'sets default code_suggestions value to true' do
|
||||
expect(settings.code_suggestions).to eq true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when setting is updated' do
|
||||
it 'persists the code suggestions setting' do
|
||||
settings.update!(code_suggestions: false)
|
||||
|
||||
expect(settings.code_suggestions).to eq false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user namespace' do
|
||||
let(:user) { create(:user) }
|
||||
let(:settings) { user.namespace.namespace_settings }
|
||||
|
||||
it 'defaults to false' do
|
||||
expect(settings.code_suggestions).to eq false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#allow_mfa_for_group' do
|
||||
let(:settings) { group.namespace_settings }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'gitlab-dangerfiles'
|
||||
require 'danger'
|
||||
require 'danger/plugins/internal/helper'
|
||||
require 'gitlab/dangerfiles/spec_helper'
|
||||
|
||||
require_relative '../../../tooling/danger/database'
|
||||
|
||||
RSpec.describe Tooling::Danger::Database, feature_category: :tooling do
|
||||
include_context "with dangerfile"
|
||||
|
||||
let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
|
||||
let(:migration_files) do
|
||||
[
|
||||
# regular migrations
|
||||
'db/migrate/20220901010203_add_widgets_table.rb',
|
||||
'db/migrate/20220909010203_add_properties_column.rb',
|
||||
'db/migrate/20220910010203_drop_tools_table.rb',
|
||||
'db/migrate/20220912010203_add_index_to_widgets_table.rb',
|
||||
|
||||
# post migrations
|
||||
'db/post_migrate/20220901010203_add_widgets_table.rb',
|
||||
'db/post_migrate/20220909010203_add_properties_column.rb',
|
||||
'db/post_migrate/20220910010203_drop_tools_table.rb',
|
||||
'db/post_migrate/20220912010203_add_index_to_widgets_table.rb',
|
||||
|
||||
# ee migrations
|
||||
'ee/db/migrate/20220901010203_add_widgets_table.rb',
|
||||
'ee/db/migrate/20220909010203_add_properties_column.rb',
|
||||
'ee/db/migrate/20220910010203_drop_tools_table.rb',
|
||||
'ee/db/migrate/20220912010203_add_index_to_widgets_table.rb',
|
||||
|
||||
# geo migrations
|
||||
'ee/db/geo/migrate/20220901010203_add_widgets_table.rb',
|
||||
'ee/db/geo/migrate/20220909010203_add_properties_column.rb',
|
||||
'ee/db/geo/migrate/20220910010203_drop_tools_table.rb',
|
||||
'ee/db/geo/migrate/20220912010203_add_index_to_widgets_table.rb'
|
||||
]
|
||||
end
|
||||
|
||||
let(:cutoff) { Date.parse('2022-10-01') - 21 }
|
||||
|
||||
subject(:database) { fake_danger.new }
|
||||
|
||||
describe '#find_migration_files_before' do
|
||||
it 'returns migrations that are before the cutoff' do
|
||||
expect(database.find_migration_files_before(migration_files, cutoff).length).to eq(8)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Tooling
|
||||
module Danger
|
||||
module Database
|
||||
TIMESTAMP_MATCHER = /(?<timestamp>\d{14})/
|
||||
MIGRATION_MATCHER = %r{\A(ee/)?db/(geo/)?(post_)?migrate/}
|
||||
|
||||
def find_migration_files_before(file_names, cutoff)
|
||||
migrations = file_names.select { |f| f.match?(MIGRATION_MATCHER) }
|
||||
migrations.select do |migration|
|
||||
next unless match = TIMESTAMP_MATCHER.match(migration)
|
||||
|
||||
timestamp = Date.parse(match[:timestamp])
|
||||
timestamp < cutoff
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue