Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-08-09 09:22:41 +00:00
parent 4b8939db3d
commit 65688a5092
63 changed files with 1588 additions and 244 deletions

View File

@ -22,6 +22,273 @@ Graphql/Descriptions:
- 'ee/app/graphql/types/vulnerability_report_type_enum.rb'
- 'ee/app/graphql/types/vulnerability_severity_enum.rb'
- 'ee/app/graphql/types/vulnerability_state_enum.rb'
- 'app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb'
- 'app/graphql/mutations/alert_management/alerts/set_assignees.rb'
- 'app/graphql/mutations/alert_management/base.rb'
- 'app/graphql/mutations/alert_management/http_integration/create.rb'
- 'app/graphql/mutations/alert_management/http_integration/destroy.rb'
- 'app/graphql/mutations/alert_management/http_integration/http_integration_base.rb'
- 'app/graphql/mutations/alert_management/http_integration/reset_token.rb'
- 'app/graphql/mutations/alert_management/http_integration/update.rb'
- 'app/graphql/mutations/alert_management/prometheus_integration/create.rb'
- 'app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb'
- 'app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb'
- 'app/graphql/mutations/alert_management/prometheus_integration/update.rb'
- 'app/graphql/mutations/alert_management/update_alert_status.rb'
- 'app/graphql/mutations/award_emojis/base.rb'
- 'app/graphql/mutations/boards/common_mutation_arguments.rb'
- 'app/graphql/mutations/boards/create.rb'
- 'app/graphql/mutations/boards/destroy.rb'
- 'app/graphql/mutations/boards/lists/destroy.rb'
- 'app/graphql/mutations/boards/update.rb'
- 'app/graphql/mutations/ci/ci_cd_settings_update.rb'
- 'app/graphql/mutations/ci/job/base.rb'
- 'app/graphql/mutations/ci/job/play.rb'
- 'app/graphql/mutations/ci/job/retry.rb'
- 'app/graphql/mutations/ci/job_token_scope/add_project.rb'
- 'app/graphql/mutations/ci/job_token_scope/remove_project.rb'
- 'app/graphql/mutations/ci/pipeline/base.rb'
- 'app/graphql/mutations/ci/pipeline/retry.rb'
- 'app/graphql/mutations/ci/runner/update.rb'
- 'app/graphql/mutations/ci/runners_registration_token/reset.rb'
- 'app/graphql/mutations/commits/create.rb'
- 'app/graphql/mutations/concerns/mutations/assignable.rb'
- 'app/graphql/mutations/concerns/mutations/can_mutate_spammable.rb'
- 'app/graphql/mutations/concerns/mutations/resolves_subscription.rb'
- 'app/graphql/mutations/container_expiration_policies/update.rb'
- 'app/graphql/mutations/container_repositories/destroy.rb'
- 'app/graphql/mutations/custom_emoji/create.rb'
- 'app/graphql/mutations/design_management/base.rb'
- 'app/graphql/mutations/design_management/delete.rb'
- 'app/graphql/mutations/design_management/move.rb'
- 'app/graphql/mutations/design_management/upload.rb'
- 'app/graphql/mutations/discussions/toggle_resolve.rb'
- 'app/graphql/mutations/environments/canary_ingress/update.rb'
- 'app/graphql/mutations/groups/update.rb'
- 'app/graphql/mutations/issues/base.rb'
- 'app/graphql/mutations/issues/create.rb'
- 'app/graphql/mutations/issues/move.rb'
- 'app/graphql/mutations/issues/set_due_date.rb'
- 'app/graphql/mutations/issues/set_subscription.rb'
- 'app/graphql/mutations/issues/update.rb'
- 'app/graphql/mutations/jira_import/import_users.rb'
- 'app/graphql/mutations/jira_import/start.rb'
- 'app/graphql/mutations/labels/create.rb'
- 'app/graphql/mutations/merge_requests/accept.rb'
- 'app/graphql/mutations/merge_requests/base.rb'
- 'app/graphql/mutations/merge_requests/create.rb'
- 'app/graphql/mutations/merge_requests/reviewer_rereview.rb'
- 'app/graphql/mutations/merge_requests/set_labels.rb'
- 'app/graphql/mutations/merge_requests/set_milestone.rb'
- 'app/graphql/mutations/merge_requests/set_subscription.rb'
- 'app/graphql/mutations/merge_requests/update.rb'
- 'app/graphql/mutations/metrics/dashboard/annotations/create.rb'
- 'app/graphql/mutations/namespace/package_settings/update.rb'
- 'app/graphql/mutations/notes/base.rb'
- 'app/graphql/mutations/notes/create/base.rb'
- 'app/graphql/mutations/notes/create/note.rb'
- 'app/graphql/mutations/notes/destroy.rb'
- 'app/graphql/mutations/notes/reposition_image_diff_note.rb'
- 'app/graphql/mutations/notes/update/base.rb'
- 'app/graphql/mutations/notes/update/note.rb'
- 'app/graphql/mutations/release_asset_links/create.rb'
- 'app/graphql/mutations/release_asset_links/delete.rb'
- 'app/graphql/mutations/release_asset_links/update.rb'
- 'app/graphql/mutations/releases/create.rb'
- 'app/graphql/mutations/releases/delete.rb'
- 'app/graphql/mutations/releases/update.rb'
- 'app/graphql/mutations/snippets/base.rb'
- 'app/graphql/mutations/snippets/create.rb'
- 'app/graphql/mutations/snippets/destroy.rb'
- 'app/graphql/mutations/snippets/mark_as_spam.rb'
- 'app/graphql/mutations/snippets/update.rb'
- 'app/graphql/mutations/todos/create.rb'
- 'app/graphql/mutations/todos/mark_done.rb'
- 'app/graphql/mutations/todos/restore.rb'
- 'app/graphql/mutations/todos/restore_many.rb'
- 'app/graphql/mutations/user_callouts/create.rb'
- 'app/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver.rb'
- 'app/graphql/resolvers/blobs_resolver.rb'
- 'app/graphql/resolvers/board_resolver.rb'
- 'app/graphql/resolvers/ci/config_resolver.rb'
- 'app/graphql/resolvers/concerns/resolves_snippets.rb'
- 'app/graphql/resolvers/design_management/design_at_version_resolver.rb'
- 'app/graphql/resolvers/design_management/version/design_at_version_resolver.rb'
- 'app/graphql/resolvers/design_management/version_in_collection_resolver.rb'
- 'app/graphql/resolvers/design_management/version_resolver.rb'
- 'app/graphql/resolvers/design_management/versions_resolver.rb'
- 'app/graphql/resolvers/full_path_resolver.rb'
- 'app/graphql/resolvers/labels_resolver.rb'
- 'app/graphql/resolvers/merge_requests_resolver.rb'
- 'app/graphql/resolvers/milestones_resolver.rb'
- 'app/graphql/resolvers/package_details_resolver.rb'
- 'app/graphql/resolvers/paginated_tree_resolver.rb'
- 'app/graphql/resolvers/release_resolver.rb'
- 'app/graphql/resolvers/repository_branch_names_resolver.rb'
- 'app/graphql/resolvers/snippets_resolver.rb'
- 'app/graphql/resolvers/todo_resolver.rb'
- 'app/graphql/resolvers/tree_resolver.rb'
- 'app/graphql/resolvers/users/snippets_resolver.rb'
- 'app/graphql/types/admin/analytics/usage_trends/measurement_type.rb'
- 'app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb'
- 'app/graphql/types/alert_management/alert_type.rb'
- 'app/graphql/types/award_emojis/award_emoji_type.rb'
- 'app/graphql/types/ci/config/job_restriction_type.rb'
- 'app/graphql/types/ci/config/status_enum.rb'
- 'app/graphql/types/ci/pipeline_type.rb'
- 'app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb'
- 'app/graphql/types/commit_action_type.rb'
- 'app/graphql/types/container_repository_cleanup_status_enum.rb'
- 'app/graphql/types/container_repository_tag_type.rb'
- 'app/graphql/types/container_repository_type.rb'
- 'app/graphql/types/custom_emoji_type.rb'
- 'app/graphql/types/design_management/design_at_version_type.rb'
- 'app/graphql/types/design_management/design_fields.rb'
- 'app/graphql/types/diff_paths_input_type.rb'
- 'app/graphql/types/environment_type.rb'
- 'app/graphql/types/eventable_type.rb'
- 'app/graphql/types/group_type.rb'
- 'app/graphql/types/merge_request_type.rb'
- 'app/graphql/types/metadata/kas_type.rb'
- 'app/graphql/types/milestone_wildcard_id_enum.rb'
- 'app/graphql/types/namespace_type.rb'
- 'app/graphql/types/notes/note_type.rb'
- 'app/graphql/types/notes/position_type_enum.rb'
- 'app/graphql/types/packages/composer/json_type.rb'
- 'app/graphql/types/packages/package_details_type.rb'
- 'app/graphql/types/packages/package_file_type.rb'
- 'app/graphql/types/packages/package_tag_type.rb'
- 'app/graphql/types/packages/package_type.rb'
- 'app/graphql/types/project_type.rb'
- 'app/graphql/types/prometheus_alert_type.rb'
- 'app/graphql/types/query_type.rb'
- 'app/graphql/types/range_input_type.rb'
- 'app/graphql/types/release_asset_link_shared_input_arguments.rb'
- 'app/graphql/types/release_assets_input_type.rb'
- 'app/graphql/types/release_type.rb'
- 'app/graphql/types/repository/blob_type.rb'
- 'app/graphql/types/root_storage_statistics_type.rb'
- 'app/graphql/types/snippet_type.rb'
- 'app/graphql/types/snippets/blob_type.rb'
- 'app/graphql/types/snippets/visibility_scopes_enum.rb'
- 'app/graphql/types/terraform/state_type.rb'
- 'app/graphql/types/terraform/state_version_type.rb'
- 'app/graphql/types/timelog_type.rb'
- 'app/graphql/types/todo_state_enum.rb'
- 'app/graphql/types/todo_target_enum.rb'
- 'app/graphql/types/todo_type.rb'
- 'app/graphql/types/user_interface.rb'
- 'app/graphql/types/user_merge_request_interaction_type.rb'
- 'app/graphql/types/user_state_enum.rb'
- 'ee/app/graphql/ee/mutations/alert_management/http_integration/create.rb'
- 'ee/app/graphql/ee/mutations/alert_management/http_integration/update.rb'
- 'ee/app/graphql/ee/mutations/boards/issues/issue_move_list.rb'
- 'ee/app/graphql/ee/mutations/issues/create.rb'
- 'ee/app/graphql/ee/mutations/issues/update.rb'
- 'ee/app/graphql/ee/types/alert_management/http_integration_type.rb'
- 'ee/app/graphql/ee/types/board_list_type.rb'
- 'ee/app/graphql/ee/types/board_type.rb'
- 'ee/app/graphql/ee/types/group_type.rb'
- 'ee/app/graphql/ee/types/project_type.rb'
- 'ee/app/graphql/ee/types/query_type.rb'
- 'ee/app/graphql/mutations/app_sec/fuzzing/api/ci_configuration/create.rb'
- 'ee/app/graphql/mutations/boards/epic_boards/create.rb'
- 'ee/app/graphql/mutations/boards/epic_boards/epic_move_list.rb'
- 'ee/app/graphql/mutations/boards/epic_boards/update.rb'
- 'ee/app/graphql/mutations/boards/epic_lists/destroy.rb'
- 'ee/app/graphql/mutations/boards/lists/update_limit_metrics.rb'
- 'ee/app/graphql/mutations/boards/update_epic_user_preferences.rb'
- 'ee/app/graphql/mutations/compliance_management/frameworks/create.rb'
- 'ee/app/graphql/mutations/compliance_management/frameworks/destroy.rb'
- 'ee/app/graphql/mutations/compliance_management/frameworks/update.rb'
- 'ee/app/graphql/mutations/concerns/mutations/shared_epic_arguments.rb'
- 'ee/app/graphql/mutations/dast/profiles/create.rb'
- 'ee/app/graphql/mutations/dast/profiles/update.rb'
- 'ee/app/graphql/mutations/dast_on_demand_scans/create.rb'
- 'ee/app/graphql/mutations/dast_scanner_profiles/create.rb'
- 'ee/app/graphql/mutations/dast_scanner_profiles/update.rb'
- 'ee/app/graphql/mutations/dast_site_profiles/create.rb'
- 'ee/app/graphql/mutations/dast_site_profiles/delete.rb'
- 'ee/app/graphql/mutations/dast_site_profiles/update.rb'
- 'ee/app/graphql/mutations/dast_site_tokens/create.rb'
- 'ee/app/graphql/mutations/dast_site_validations/create.rb'
- 'ee/app/graphql/mutations/dast_site_validations/revoke.rb'
- 'ee/app/graphql/mutations/epic_tree/reorder.rb'
- 'ee/app/graphql/mutations/epics/add_issue.rb'
- 'ee/app/graphql/mutations/epics/base.rb'
- 'ee/app/graphql/mutations/epics/create.rb'
- 'ee/app/graphql/mutations/epics/set_subscription.rb'
- 'ee/app/graphql/mutations/gitlab_subscriptions/activate.rb'
- 'ee/app/graphql/mutations/incident_management/escalation_policy/base.rb'
- 'ee/app/graphql/mutations/incident_management/escalation_policy/create.rb'
- 'ee/app/graphql/mutations/incident_management/escalation_policy/destroy.rb'
- 'ee/app/graphql/mutations/incident_management/escalation_policy/update.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_rotation/base.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_rotation/create.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_rotation/destroy.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_rotation/update.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_schedule/create.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_schedule/destroy.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_schedule/oncall_schedule_base.rb'
- 'ee/app/graphql/mutations/incident_management/oncall_schedule/update.rb'
- 'ee/app/graphql/mutations/issues/common_ee_mutation_arguments.rb'
- 'ee/app/graphql/mutations/issues/promote_to_epic.rb'
- 'ee/app/graphql/mutations/issues/set_iteration.rb'
- 'ee/app/graphql/mutations/iterations/cadences/create.rb'
- 'ee/app/graphql/mutations/iterations/cadences/update.rb'
- 'ee/app/graphql/mutations/iterations/create.rb'
- 'ee/app/graphql/mutations/namespaces/base.rb'
- 'ee/app/graphql/mutations/quality_management/test_cases/create.rb'
- 'ee/app/graphql/mutations/requirements_management/update_requirement.rb'
- 'ee/app/graphql/mutations/vulnerabilities/confirm.rb'
- 'ee/app/graphql/mutations/vulnerabilities/create_external_issue_link.rb'
- 'ee/app/graphql/mutations/vulnerabilities/destroy_external_issue_link.rb'
- 'ee/app/graphql/mutations/vulnerabilities/dismiss.rb'
- 'ee/app/graphql/mutations/vulnerabilities/resolve.rb'
- 'ee/app/graphql/mutations/vulnerabilities/revert_to_detected.rb'
- 'ee/app/graphql/resolvers/dora_metrics_resolver.rb'
- 'ee/app/graphql/resolvers/geo/geo_node_resolver.rb'
- 'ee/app/graphql/resolvers/network_policy_resolver.rb'
- 'ee/app/graphql/resolvers/requirements_management/requirements_resolver.rb'
- 'ee/app/graphql/types/alert_management/payload_alert_field_input_type.rb'
- 'ee/app/graphql/types/alert_management/payload_alert_mapping_field_type.rb'
- 'ee/app/graphql/types/analytics/devops_adoption/snapshot_type.rb'
- 'ee/app/graphql/types/app_sec/fuzzing/api/scan_profile_type.rb'
- 'ee/app/graphql/types/ci/code_quality_degradation_type.rb'
- 'ee/app/graphql/types/ci/minutes/namespace_monthly_usage_type.rb'
- 'ee/app/graphql/types/ci/minutes/project_monthly_usage_type.rb'
- 'ee/app/graphql/types/clusters/agent_token_type.rb'
- 'ee/app/graphql/types/clusters/agent_type.rb'
- 'ee/app/graphql/types/dast/profile_branch_type.rb'
- 'ee/app/graphql/types/dast/profile_type.rb'
- 'ee/app/graphql/types/dast/site_profile_auth_input_type.rb'
- 'ee/app/graphql/types/dast/site_profile_auth_type.rb'
- 'ee/app/graphql/types/dast_scanner_profile_type.rb'
- 'ee/app/graphql/types/dast_site_profile_type.rb'
- 'ee/app/graphql/types/epic_tree/epic_tree_node_input_type.rb'
- 'ee/app/graphql/types/epic_type.rb'
- 'ee/app/graphql/types/geo/geo_node_type.rb'
- 'ee/app/graphql/types/incident_management/escalation_policy_type.rb'
- 'ee/app/graphql/types/incident_management/escalation_rule_input_type.rb'
- 'ee/app/graphql/types/incident_management/escalation_rule_type.rb'
- 'ee/app/graphql/types/incident_management/oncall_participant_type.rb'
- 'ee/app/graphql/types/incident_management/oncall_rotation_active_period_input_type.rb'
- 'ee/app/graphql/types/incident_management/oncall_rotation_active_period_type.rb'
- 'ee/app/graphql/types/incident_management/oncall_rotation_date_input_type.rb'
- 'ee/app/graphql/types/incident_management/oncall_rotation_length_input_type.rb'
- 'ee/app/graphql/types/incident_management/oncall_user_input_type.rb'
- 'ee/app/graphql/types/move_type_enum.rb'
- 'ee/app/graphql/types/network_policy_kind_enum.rb'
- 'ee/app/graphql/types/path_lock_type.rb'
- 'ee/app/graphql/types/pipeline_security_report_finding_type.rb'
- 'ee/app/graphql/types/scanned_resource_type.rb'
- 'ee/app/graphql/types/security_report_summary_section_type.rb'
- 'ee/app/graphql/types/timebox_metrics_type.rb'
- 'ee/app/graphql/types/vulnerability/issue_link_type.rb'
- 'ee/app/graphql/types/vulnerability_details/commit_type.rb'
- 'ee/app/graphql/types/vulnerability_type.rb'
- 'ee/app/graphql/types/vulnerable_dependency_type.rb'
- 'ee/app/graphql/types/vulnerable_package_type.rb'
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
Rails/SaveBang:

View File

@ -1 +1 @@
3af862d452b894f08d1651944d763834a5c35ab8
23842e500b6c90e1f462c78b497a8af8d1d6c8a6

View File

@ -1,12 +1,12 @@
<script>
import { GlModal, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { GlButton, GlModal, GlTooltipDirective } from '@gitlab/ui';
import { mapActions } from 'vuex';
import { __, sprintf } from '~/locale';
import ListItem from './list_item.vue';
export default {
components: {
GlIcon,
GlButton,
ListItem,
GlModal,
},
@ -70,7 +70,7 @@ export default {
<div class="d-flex align-items-center flex-fill">
<strong> {{ titleText }} </strong>
<div class="d-flex ml-auto">
<button
<gl-button
v-if="!stagedList"
v-gl-tooltip
:title="__('Discard all changes')"
@ -79,15 +79,14 @@ export default {
:class="{
'disabled-content': !filesLength,
}"
type="button"
class="d-flex ide-staged-action-btn p-0 border-0 align-items-center"
class="gl-shadow-none!"
category="tertiary"
icon="remove-all"
data-placement="bottom"
data-container="body"
data-boundary="viewport"
@click="openDiscardModal"
>
<gl-icon :size="16" name="remove-all" class="ml-auto mr-auto position-top-0" />
</button>
/>
</div>
</div>
</header>

View File

@ -4,14 +4,12 @@ import { FILTERED_SEARCH } from '~/pages/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import projectSelect from '~/project_select';
document.addEventListener('DOMContentLoaded', () => {
addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys, true);
addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys, true);
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
});
projectSelect();
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
});
projectSelect();

View File

@ -1,3 +1,3 @@
import projectSelect from '~/project_select';
document.addEventListener('DOMContentLoaded', projectSelect);
projectSelect();

View File

@ -2,7 +2,7 @@ import GroupsList from '~/groups_list';
import Landing from '~/landing';
import initGroupsList from '../../../groups';
document.addEventListener('DOMContentLoaded', () => {
function exploreGroups() {
new GroupsList(); // eslint-disable-line no-new
initGroupsList();
const landingElement = document.querySelector('.js-explore-groups-landing');
@ -13,4 +13,6 @@ document.addEventListener('DOMContentLoaded', () => {
'explore_groups_landing_dismissed',
);
exploreGroupsLanding.toggle();
});
}
exploreGroups();

View File

@ -2,7 +2,5 @@ import $ from 'jquery';
import docs from '~/docs/docs_bundle';
import VersionCheckImage from '~/version_check_image';
document.addEventListener('DOMContentLoaded', () => {
docs();
VersionCheckImage.bindErrorEvent($('img.js-version-status-badge'));
});
docs();
VersionCheckImage.bindErrorEvent($('img.js-version-status-badge'));

View File

@ -1,3 +1,3 @@
import initUIKit from '~/ui_development_kit';
document.addEventListener('DOMContentLoaded', initUIKit);
initUIKit();

View File

@ -2,7 +2,7 @@ import Vue from 'vue';
import { initStoreFromElement, initPropsFromElement } from '~/import_entities/import_projects';
import BitbucketStatusTable from '~/import_entities/import_projects/components/bitbucket_status_table.vue';
document.addEventListener('DOMContentLoaded', () => {
function importBitBucket() {
const mountElement = document.getElementById('import-projects-mount-element');
if (!mountElement) return undefined;
@ -16,4 +16,6 @@ document.addEventListener('DOMContentLoaded', () => {
return createElement(BitbucketStatusTable, { attrs });
},
});
});
}
importBitBucket();

View File

@ -2,7 +2,7 @@ import Vue from 'vue';
import { initStoreFromElement, initPropsFromElement } from '~/import_entities/import_projects';
import BitbucketServerStatusTable from './components/bitbucket_server_status_table.vue';
document.addEventListener('DOMContentLoaded', () => {
function BitbucketServerStatus() {
const mountElement = document.getElementById('import-projects-mount-element');
if (!mountElement) return undefined;
@ -19,4 +19,6 @@ document.addEventListener('DOMContentLoaded', () => {
});
},
});
});
}
BitbucketServerStatus();

View File

@ -1,7 +1,5 @@
import mountImportProjectsTable from '~/import_entities/import_projects';
document.addEventListener('DOMContentLoaded', () => {
const mountElement = document.getElementById('import-projects-mount-element');
const mountElement = document.getElementById('import-projects-mount-element');
mountImportProjectsTable(mountElement);
});
mountImportProjectsTable(mountElement);

View File

@ -1,7 +1,5 @@
import mountImportProjectsTable from '~/import_entities/import_projects';
document.addEventListener('DOMContentLoaded', () => {
const mountElement = document.getElementById('import-projects-mount-element');
const mountElement = document.getElementById('import-projects-mount-element');
mountImportProjectsTable(mountElement);
});
mountImportProjectsTable(mountElement);

View File

@ -1,3 +1,3 @@
import initGitLabImportProject from '~/projects/project_import_gitlab_project';
document.addEventListener('DOMContentLoaded', initGitLabImportProject);
initGitLabImportProject();

View File

@ -1,7 +1,5 @@
import mountImportProjectsTable from '~/import_entities/import_projects';
document.addEventListener('DOMContentLoaded', () => {
const mountElement = document.getElementById('import-projects-mount-element');
const mountElement = document.getElementById('import-projects-mount-element');
mountImportProjectsTable(mountElement);
});
mountImportProjectsTable(mountElement);

View File

@ -1,3 +1,3 @@
import { mount2faAuthentication } from '~/authentication/mount_2fa';
document.addEventListener('DOMContentLoaded', mount2faAuthentication);
mount2faAuthentication();

View File

@ -2,16 +2,14 @@ import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import PrometheusAlerts from '~/prometheus_alerts';
import CustomMetrics from '~/prometheus_metrics/custom_metrics';
document.addEventListener('DOMContentLoaded', () => {
const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
integrationSettingsForm.init();
const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
integrationSettingsForm.init();
const prometheusSettingsSelector = '.js-prometheus-metrics-monitoring';
const prometheusSettingsWrapper = document.querySelector(prometheusSettingsSelector);
if (prometheusSettingsWrapper) {
const customMetrics = new CustomMetrics(prometheusSettingsSelector);
customMetrics.init();
}
const prometheusSettingsSelector = '.js-prometheus-metrics-monitoring';
const prometheusSettingsWrapper = document.querySelector(prometheusSettingsSelector);
if (prometheusSettingsWrapper) {
const customMetrics = new CustomMetrics(prometheusSettingsSelector);
customMetrics.init();
}
PrometheusAlerts();
});
PrometheusAlerts();

View File

@ -1,3 +1,3 @@
import { mount2faAuthentication } from '~/authentication/mount_2fa';
document.addEventListener('DOMContentLoaded', mount2faAuthentication);
mount2faAuthentication();

View File

@ -7,18 +7,16 @@ import preserveUrlFragment from './preserve_url_fragment';
import SigninTabsMemoizer from './signin_tabs_memoizer';
import UsernameValidator from './username_validator';
document.addEventListener('DOMContentLoaded', () => {
new UsernameValidator(); // eslint-disable-line no-new
new LengthValidator(); // eslint-disable-line no-new
new SigninTabsMemoizer(); // eslint-disable-line no-new
new NoEmojiValidator(); // eslint-disable-line no-new
new UsernameValidator(); // eslint-disable-line no-new
new LengthValidator(); // eslint-disable-line no-new
new SigninTabsMemoizer(); // eslint-disable-line no-new
new NoEmojiValidator(); // eslint-disable-line no-new
new OAuthRememberMe({
container: $('.omniauth-container'),
}).bindEvents();
new OAuthRememberMe({
container: $('.omniauth-container'),
}).bindEvents();
// Save the URL fragment from the current window location. This will be present if the user was
// redirected to sign-in after attempting to access a protected URL that included a fragment.
preserveUrlFragment(window.location.hash);
initVueAlerts();
});
// Save the URL fragment from the current window location. This will be present if the user was
// redirected to sign-in after attempting to access a protected URL that included a fragment.
preserveUrlFragment(window.location.hash);
initVueAlerts();

View File

@ -26,9 +26,10 @@ class Admin::UsersController < Admin::ApplicationController
def show
end
# rubocop: disable CodeReuse/ActiveRecord
def projects
@personal_projects = user.personal_projects
@joined_projects = user.projects.joined(@user)
@personal_projects = user.personal_projects.includes(:topics)
@joined_projects = user.projects.joined(@user).includes(:topics)
end
def keys

View File

@ -81,7 +81,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def preload_associations(projects)
projects.includes(:route, :creator, :group, namespace: [:route, :owner]).preload(:project_feature)
projects.includes(:route, :creator, :group, :topics, namespace: [:route, :owner]).preload(:project_feature)
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -87,7 +87,7 @@ class Explore::ProjectsController < Explore::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def preload_associations(projects)
projects.includes(:route, :creator, :group, :project_feature, namespace: [:route, :owner])
projects.includes(:route, :creator, :group, :project_feature, :topics, namespace: [:route, :owner])
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -65,17 +65,13 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
# See https://developer.atlassian.com/cloud/jira/software/modules/development-tool/
def development_tool_module
actions = {}
if JiraConnect::BranchesController.feature_enabled?(current_user)
actions[:createBranch] = {
templateUrl: new_jira_connect_branch_url + '?issue_key={issue.key}&issue_summary={issue.summary}'
}
end
{
jiraDevelopmentTool: {
actions: actions,
actions: {
createBranch: {
templateUrl: new_jira_connect_branch_url + '?issue_key={issue.key}&issue_summary={issue.summary}'
}
},
key: 'gitlab-development-tool',
application: { value: 'GitLab' },
name: { value: 'GitLab' },

View File

@ -3,18 +3,12 @@
# NOTE: This controller does not inherit from JiraConnect::ApplicationController
# because we don't receive a JWT for this action, so we rely on standard GitLab authentication.
class JiraConnect::BranchesController < ApplicationController
before_action :feature_enabled!
feature_category :integrations
def new
@new_branch_data = new_branch_data
end
def self.feature_enabled?(user)
Feature.enabled?(:jira_connect_create_branch, user, default_enabled: :yaml)
end
private
def initial_branch_name
@ -32,8 +26,4 @@ class JiraConnect::BranchesController < ApplicationController
success_state_svg_path: ActionController::Base.helpers.image_path('illustrations/merge_requests.svg')
}
end
def feature_enabled!
render_404 unless self.class.feature_enabled?(current_user)
end
end

View File

@ -99,7 +99,7 @@ class Projects::ForksController < Projects::ApplicationController
current_user: current_user
).execute
forks.includes(:route, :creator, :group, namespace: [:route, :owner])
forks.includes(:route, :creator, :group, :topics, namespace: [:route, :owner])
end
def fork_service

View File

@ -434,9 +434,9 @@ class Event < ApplicationRecord
def design_action_names
{
created: _('uploaded'),
updated: _('revised'),
destroyed: _('deleted')
created: _('added'),
updated: _('updated'),
destroyed: _('removed')
}
end

View File

@ -397,16 +397,16 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
end
def topics_to_show
project.topic_list.take(MAX_TOPICS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
project_topic_list.take(MAX_TOPICS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
end
def topics_not_shown
project.topic_list - topics_to_show
project_topic_list - topics_to_show
end
def count_of_extra_topics_not_shown
if project.topic_list.count > MAX_TOPICS_TO_SHOW
project.topic_list.count - MAX_TOPICS_TO_SHOW
if project_topic_list.count > MAX_TOPICS_TO_SHOW
project_topic_list.count - MAX_TOPICS_TO_SHOW
else
0
end
@ -486,6 +486,12 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
**additional_params
)
end
def project_topic_list
strong_memoize(:project_topic_list) do
project.topics.map(&:name)
end
end
end
ProjectPresenter.prepend_mod_with('ProjectPresenter')

View File

@ -22,8 +22,9 @@ module Search
filters: { state: params[:state], confidential: params[:confidential] })
end
# rubocop: disable CodeReuse/ActiveRecord
def projects
@projects ||= ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute
@projects ||= ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute.includes(:topics, :taggings)
end
def allowed_scopes

View File

@ -1,6 +1,5 @@
- empty_repo = @project.empty_repo?
- show_auto_devops_callout = show_auto_devops_callout?(@project)
- max_project_topic_length = 15
- emails_disabled = @project.emails_disabled?
- cache_enabled = Feature.enabled?(:cache_home_panel, @project, type: :development, default_enabled: :yaml)
@ -25,24 +24,8 @@
%span.access-request-links.gl-ml-3
= render 'shared/members/access_request_links', source: @project
- if @project.topic_list.present?
= cache_if(cache_enabled, [@project, :topic_list], expires_in: 1.day) do
%span.home-panel-topic-list.mt-2.w-100.d-inline-flex.gl-font-base.gl-font-weight-normal.gl-align-items-center
= sprite_icon('tag', css_class: 'icon gl-relative gl-mr-2')
- @project.topics_to_show.each do |topic|
- project_topics_classes = "badge badge-pill badge-secondary gl-mr-2"
- explore_project_topic_path = explore_projects_path(topic: topic)
- if topic.length > max_project_topic_length
%a{ class: "#{ project_topics_classes } str-truncated-30 has-tooltip", data: { container: "body" }, title: topic, href: explore_project_topic_path, itemprop: 'keywords' }
= topic.titleize
- else
%a{ class: project_topics_classes, href: explore_project_topic_path, itemprop: 'keywords' }
= topic.titleize
- if @project.has_extra_topics?
.text-nowrap.has-tooltip{ data: { container: 'body' }, title: @project.has_extra_topics? ? @project.topics_not_shown.join(', ') : nil }
= _("+ %{count} more") % { count: @project.count_of_extra_topics_not_shown }
.gl-mt-3.gl-pl-3.gl-w-full
= render "shared/projects/topics", project: @project, cache_enabled: cache_enabled
= cache_if(cache_enabled, [@project, :buttons, current_user, @notification_setting], expires_in: 1.day) do
.project-repo-buttons.gl-display-flex.gl-justify-content-md-end.gl-align-items-start.gl-flex-wrap.gl-mt-5

View File

@ -65,6 +65,10 @@
.description.d-none.d-sm-block.gl-mr-3
= markdown_field(project, :description)
- if project.topics.any?
.gl-mt-2
= render "shared/projects/topics", project: project.present(current_user: current_user)
= render_if_exists 'shared/projects/removed', project: project
.controls.d-flex.flex-sm-column.align-items-center.align-items-sm-end.flex-wrap.flex-shrink-0.text-secondary{ class: css_controls_class.join(" ") }

View File

@ -0,0 +1,32 @@
- cache_enabled = false unless local_assigns[:cache_enabled] == true
- max_project_topic_length = 15
- project_topics_classes = "badge badge-pill badge-secondary gl-mr-2"
- if project.topics.present?
= cache_if(cache_enabled, [project, :topic_list], expires_in: 1.day) do
%span.gl-w-full.gl-display-inline-flex.gl-font-base.gl-font-weight-normal.gl-align-items-center{ 'data-testid': 'project_topic_list' }
= sprite_icon('tag', css_class: 'icon gl-relative gl-mr-2')
- project.topics_to_show.each do |topic|
- explore_project_topic_path = explore_projects_path(topic: topic)
- if topic.length > max_project_topic_length
%a{ class: "#{ project_topics_classes } str-truncated-30 has-tooltip", data: { container: "body" }, title: topic, href: explore_project_topic_path, itemprop: 'keywords' }
= truncate(topic, length: max_project_topic_length)
- else
%a{ class: project_topics_classes, href: explore_project_topic_path, itemprop: 'keywords' }
= topic
- if project.has_extra_topics?
- title = _('More topics')
- content = capture do
%span.gl-display-inline-flex
- project.topics_not_shown.each do |topic|
- explore_project_topic_path = explore_projects_path(topic: topic)
- if topic.length > max_project_topic_length
%a{ class: "#{ project_topics_classes } gl-mb-3 str-truncated has-tooltip", data: { container: "body" }, title: topic, href: explore_project_topic_path, itemprop: 'keywords' }
= truncate(topic, length: max_project_topic_length)
- else
%a{ class: "#{ project_topics_classes } gl-mb-3", href: explore_project_topic_path, itemprop: 'keywords' }
= topic
.text-nowrap{ role: 'button', tabindex: 0, data: { toggle: 'popover', html: 'true', placement: 'top', title: title, content: content } }
= _("+ %{count} more") % { count: project.count_of_extra_topics_not_shown }

View File

@ -1,8 +0,0 @@
---
name: jira_connect_create_branch
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66032
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/336191
milestone: '14.2'
type: development
group: group::ecosystem
default_enabled: false

View File

@ -837,7 +837,7 @@ descriptions:
- Mention the name of the resource in the description. Example:
`'Labels of the issue'` (issue being the resource).
- Use `"{x} of the {y}"` where possible. Example: `'Title of the issue'`.
Do not start descriptions with `The`.
Do not start descriptions with `The` or `A`, for consistency and conciseness.
- Descriptions of `GraphQL::Types::Boolean` fields should answer the question: "What does
this field do?". Example: `'Indicates project has a Git repository'`.
- Always include the word `"timestamp"` when describing an argument or

View File

@ -1145,3 +1145,7 @@ Note that the metrics linked here are GitLab-internal only:
- [Size](https://thanos.gitlab.net/graph?g0.range_input=2h&g0.max_source_resolution=0s&g0.expr=topk(500%2C%20max%20by%20(relname)%20(pg_total_relation_size_bytes%7Benvironment%3D%22gprd%22%7D))&g0.tab=1) is greater than 10 GB
Any table which has some high read operation compared to current [high-traffic tables](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L4) might be a good candidate.
As a general rule, we discourage adding columns to high-traffic tables that are purely for
analytics or reporting of GitLab.com. This can have negative performance impacts for all
self-managed instances without providing direct feature value to them.

View File

@ -37,7 +37,8 @@ After the integration is [set up on GitLab and Jira](#configure-the-integration)
- Refer to any Jira issue by its ID (in uppercase) in GitLab branch names,
commit messages, and merge request titles.
- See the linked branches, commits, and merge requests in Jira issues:
- See the linked branches, commits, and merge requests in Jira issues.
- Create GitLab branches from Jira issues ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66032) in GitLab 14.2).
At this time, merge requests are called "pull requests" in Jira issues.
This name may change in a future Jira release.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -49,13 +49,14 @@ To set up the Jira development panel integration:
| Capability | Jira integration | Jira Development panel integration |
|-|-|-|
| Mention a Jira issue ID in a GitLab commit or merge request, and a link to the Jira issue is created. | Yes. | No. |
| Mention a Jira issue ID in GitLab and the Jira issue shows the GitLab issue or merge request. | Yes. A Jira comment with the GitLab issue or MR title links to GitLab. The first mention is also added to the Jira issue under **Web links**. | Yes, in the issue's Development panel. |
| Mention a Jira issue ID in a GitLab commit message and the Jira issue shows the commit message. | Yes. The entire commit message is displayed in the Jira issue as a comment and under **Web links**. Each message links back to the commit in GitLab. | Yes, in the issue's Development panel and optionally with a custom comment on the Jira issue using Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html). |
| Mention a Jira issue ID in GitLab and the Jira issue shows the GitLab issue or merge request. | Yes. A Jira comment with the GitLab issue or MR title links to GitLab. The first mention is also added to the Jira issue under **Web links**. | Yes, in the issue's [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/). |
| Mention a Jira issue ID in a GitLab commit message and the Jira issue shows the commit message. | Yes. The entire commit message is displayed in the Jira issue as a comment and under **Web links**. Each message links back to the commit in GitLab. | Yes, in the issue's [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/) and optionally with a custom comment on the Jira issue using Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html). |
| Mention a Jira issue ID in a GitLab branch name and the Jira issue shows the branch name. | No. | Yes, in the issue's [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/). |
| Add Jira time tracking to an issue. | No. | Yes. Time can be specified using Jira Smart Commits. |
| Use a Git commit or merge request to transition or close a Jira issue. | Yes. Only a single transition type, typically configured to close the issue by setting it to Done. | Yes. Transition to any state using Jira Smart Commits. |
| Display a list of Jira issues. | Yes. **(PREMIUM)** | No. |
| Create a Jira issue from a vulnerability or finding. | Yes. **(ULTIMATE)** | No. |
| Create a GitLab branch from a Jira issue. | No. | Yes, in the issue's [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/). |
## Authentication in Jira

View File

@ -13,7 +13,8 @@ module Gitlab
# balancer with said hosts. Requests may continue to use the old hosts
# until they complete.
class ServiceDiscovery
attr_reader :interval, :record, :record_type, :disconnect_timeout
attr_reader :interval, :record, :record_type, :disconnect_timeout,
:load_balancer
MAX_SLEEP_ADJUSTMENT = 10
@ -40,7 +41,17 @@ module Gitlab
# disconnect_timeout - The time after which an old host should be
# forcefully disconnected.
# use_tcp - Use TCP instaed of UDP to look up resources
def initialize(nameserver:, port:, record:, record_type: 'A', interval: 60, disconnect_timeout: 120, use_tcp: false)
# load_balancer - The load balancer instance to use
def initialize(
nameserver:,
port:,
record:,
record_type: 'A',
interval: 60,
disconnect_timeout: 120,
use_tcp: false,
load_balancer: LoadBalancing.proxy.load_balancer
)
@nameserver = nameserver
@port = port
@record = record
@ -48,6 +59,7 @@ module Gitlab
@interval = interval
@disconnect_timeout = disconnect_timeout
@use_tcp = use_tcp
@load_balancer = load_balancer
end
def start
@ -147,10 +159,6 @@ module Gitlab
end.sort
end
def load_balancer
LoadBalancing.proxy.load_balancer
end
def resolver
@resolver ||= Net::DNS::Resolver.new(
nameservers: Resolver.new(@nameserver).resolve,

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :product_intelligence do
# @example
# bundle exec rake gitlab:product_intelligence:activate_metrics MILESTONE=14.0
desc 'GitLab | Product Intelligence | Update milestone metrics status to data_available'
task activate_metrics: :environment do
milestone = ENV['MILESTONE']
raise "Please supply the MILESTONE env var".color(:red) unless milestone.present?
Gitlab::Usage::MetricDefinition.definitions.values.each do |metric|
next if metric.attributes[:milestone] != milestone || metric.attributes[:status] != 'implemented'
metric.attributes[:status] = 'data_available'
path = metric.path
File.open(path, "w") { |file| file << metric.to_h.deep_stringify_keys.to_yaml }
end
puts "Task completed successfully"
end
end
end

View File

@ -21619,6 +21619,9 @@ msgstr ""
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
msgstr ""
msgid "More topics"
msgstr ""
msgid "Most relevant"
msgstr ""
@ -38487,6 +38490,9 @@ msgstr[1] ""
msgid "access:"
msgstr ""
msgid "added"
msgstr ""
msgid "added %{created_at_timeago}"
msgstr ""
@ -39849,6 +39855,9 @@ msgstr ""
msgid "remove weight"
msgstr ""
msgid "removed"
msgstr ""
msgid "removed a Zoom call from this issue"
msgstr ""
@ -39869,9 +39878,6 @@ msgstr ""
msgid "reset it."
msgstr ""
msgid "revised"
msgstr ""
msgid "satisfied"
msgstr ""
@ -40043,9 +40049,6 @@ msgstr ""
msgid "updated %{time_ago}"
msgstr ""
msgid "uploaded"
msgstr ""
msgid "uploads"
msgstr ""

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
$:.unshift(File.expand_path('lib', __dir__))
Gem::Specification.new do |spec|
spec.name = 'chemlab-library-gitlab'
spec.version = '0.1.1'
spec.authors = ['GitLab Quality']
spec.email = ['quality@gitlab.com']
spec.required_ruby_version = '>= 2.5' # rubocop:disable Gemspec/RequiredRubyVersion
spec.summary = 'Chemlab Page Libraries for GitLab'
spec.homepage = 'https://gitlab.com/'
spec.license = 'MIT'
spec.files = `git ls-files -- lib/*`.split("\n")
spec.require_paths = ['lib']
spec.add_runtime_dependency 'chemlab', '~> 0.7'
end

20
qa/lib/gitlab.rb Normal file
View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
# Chemlab Page Libraries for GitLab
module Gitlab
module Page
module Main
autoload :Login, 'gitlab/page/main/login'
end
module Subscriptions
autoload :New, 'gitlab/page/subscriptions/new'
end
module Group
module Settings
autoload :Billing, 'gitlab/page/group/settings/billing'
end
end
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Gitlab
module Page
module Group
module Settings
class Billing < Chemlab::Page
# TODO: Supplant with data-qa-selectors
h4 :billing_plan_header, css: 'div.billing-plan-header h4'
link :start_your_free_trial
link :upgrade_to_premium, css: '[data-testid="plan-card-premium"] a.billing-cta-purchase-new'
link :upgrade_to_ultimate, css: '[data-testid="plan-card-ultimate"] a.billing-cta-purchase-new'
end
end
end
end
end

View File

@ -0,0 +1,107 @@
# frozen_string_literal: true
module Gitlab
module Page
module Group
module Settings
module Billing
# @note Defined as +h4 :billing_plan_header+
# @return [String] The text content or value of +billing_plan_header+
def billing_plan_header
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing.billing_plan_header_element).to exist
# end
# @return [Watir::H4] The raw +H4+ element
def billing_plan_header_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing).to be_billing_plan_header
# end
# @return [Boolean] true if the +billing_plan_header+ element is present on the page
def billing_plan_header?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +link :start_your_free_trial+
# Clicks +start_your_free_trial+
def start_your_free_trial
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing.start_your_free_trial_element).to exist
# end
# @return [Watir::Link] The raw +Link+ element
def start_your_free_trial_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing).to be_start_your_free_trial
# end
# @return [Boolean] true if the +start_your_free_trial+ element is present on the page
def start_your_free_trial?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +link :upgrade_to_premium+
# Clicks +upgrade_to_premium+
def upgrade_to_premium
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing.upgrade_to_premium_element).to exist
# end
# @return [Watir::Link] The raw +Link+ element
def upgrade_to_premium_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing).to be_upgrade_to_premium
# end
# @return [Boolean] true if the +upgrade_to_premium+ element is present on the page
def upgrade_to_premium?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +link :upgrade_to_ultimate+
# Clicks +upgrade_to_ultimate+
def upgrade_to_ultimate
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing.upgrade_to_ultimate_element).to exist
# end
# @return [Watir::Link] The raw +Link+ element
def upgrade_to_ultimate_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::Billing.perform do |billing|
# expect(billing).to be_upgrade_to_ultimate
# end
# @return [Boolean] true if the +upgrade_to_ultimate+ element is present on the page
def upgrade_to_ultimate?
# This is a stub, used for indexing. The method is dynamically generated.
end
end
end
end
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Gitlab
module Page
module Main
class Login < Chemlab::Page
path '/users/sign_in'
text_field :login_field
text_field :password_field
button :sign_in_button
def sign_in_as(username:, password:)
self.login_field = username
self.password_field = password
sign_in_button
end
end
end
end
end

View File

@ -0,0 +1,101 @@
# frozen_string_literal: true
module Gitlab
module Page
module Main
module Login
# @note Defined as +text_field :login_field+
# @return [String] The text content or value of +login_field+
def login_field
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of login_field
# @example
# Gitlab::Page::Main::Login.perform do |login|
# login.login_field = 'value'
# end
# @param value [String] The value to set.
def login_field=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Login.perform do |login|
# expect(login.login_field_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def login_field_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Login.perform do |login|
# expect(login).to be_login_field
# end
# @return [Boolean] true if the +login_field+ element is present on the page
def login_field?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :password_field+
# @return [String] The text content or value of +password_field+
def password_field
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of password_field
# @example
# Gitlab::Page::Main::Login.perform do |login|
# login.password_field = 'value'
# end
# @param value [String] The value to set.
def password_field=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Login.perform do |login|
# expect(login.password_field_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def password_field_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Login.perform do |login|
# expect(login).to be_password_field
# end
# @return [Boolean] true if the +password_field+ element is present on the page
def password_field?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +button :sign_in_button+
# Clicks +sign_in_button+
def sign_in_button
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Login.perform do |login|
# expect(login.sign_in_button_element).to exist
# end
# @return [Watir::Button] The raw +Button+ element
def sign_in_button_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Main::Login.perform do |login|
# expect(login).to be_sign_in_button
# end
# @return [Boolean] true if the +sign_in_button+ element is present on the page
def sign_in_button?
# This is a stub, used for indexing. The method is dynamically generated.
end
end
end
end
end

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
module Gitlab
module Page
module Subscriptions
class New < Chemlab::Page
path '/subscriptions/new'
# Subscription Details
select :plan_name
select :group_name
text_field :number_of_users
button :continue_to_billing, text: /Continue to billing/
# Billing address
select :country
text_field :street_address_1
text_field :street_address_2
text_field :city
select :state
text_field :zip_code
button :continue_to_payment, text: /Continue to payment/
# Payment method
# TODO: Revisit when https://gitlab.com/gitlab-org/quality/chemlab/-/issues/6 is closed
iframe :payment_form, id: 'z_hppm_iframe'
text_field(:name_on_card) { payment_form_element.text_field(id: 'input-creditCardHolderName') }
text_field(:card_number) { payment_form_element.text_field(id: 'input-creditCardNumber') }
select(:expiration_month) { payment_form_element.select(id: 'input-creditCardExpirationMonth') }
select(:expiration_year) { payment_form_element.select(id: 'input-creditCardExpirationYear') }
text_field(:cvv) { payment_form_element.text_field(id: 'input-cardSecurityCode') }
link(:review_your_order) { payment_form_element.link(text: /Review your order/) }
# ENDTODO
# Confirmation
button :confirm_purchase, text: /Confirm purchase/
end
end
end
end

View File

@ -0,0 +1,545 @@
# frozen_string_literal: true
module Gitlab
module Page
module Subscriptions
module New
# @note Defined as +select :plan_name+
# @return [String] The text content or value of +plan_name+
def plan_name
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.plan_name_element).to exist
# end
# @return [Watir::Select] The raw +Select+ element
def plan_name_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_plan_name
# end
# @return [Boolean] true if the +plan_name+ element is present on the page
def plan_name?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +select :group_name+
# @return [String] The text content or value of +group_name+
def group_name
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.group_name_element).to exist
# end
# @return [Watir::Select] The raw +Select+ element
def group_name_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_group_name
# end
# @return [Boolean] true if the +group_name+ element is present on the page
def group_name?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :number_of_users+
# @return [String] The text content or value of +number_of_users+
def number_of_users
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of number_of_users
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.number_of_users = 'value'
# end
# @param value [String] The value to set.
def number_of_users=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.number_of_users_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def number_of_users_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_number_of_users
# end
# @return [Boolean] true if the +number_of_users+ element is present on the page
def number_of_users?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +button :continue_to_billing+
# Clicks +continue_to_billing+
def continue_to_billing
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.continue_to_billing_element).to exist
# end
# @return [Watir::Button] The raw +Button+ element
def continue_to_billing_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_continue_to_billing
# end
# @return [Boolean] true if the +continue_to_billing+ element is present on the page
def continue_to_billing?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +select :country+
# @return [String] The text content or value of +country+
def country
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.country_element).to exist
# end
# @return [Watir::Select] The raw +Select+ element
def country_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_country
# end
# @return [Boolean] true if the +country+ element is present on the page
def country?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :street_address_1+
# @return [String] The text content or value of +street_address_1+
def street_address_1
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of street_address_1
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.street_address_1 = 'value'
# end
# @param value [String] The value to set.
def street_address_1=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.street_address_1_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def street_address_1_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_street_address_1
# end
# @return [Boolean] true if the +street_address_1+ element is present on the page
def street_address_1?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :street_address_2+
# @return [String] The text content or value of +street_address_2+
def street_address_2
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of street_address_2
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.street_address_2 = 'value'
# end
# @param value [String] The value to set.
def street_address_2=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.street_address_2_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def street_address_2_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_street_address_2
# end
# @return [Boolean] true if the +street_address_2+ element is present on the page
def street_address_2?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :city+
# @return [String] The text content or value of +city+
def city
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of city
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.city = 'value'
# end
# @param value [String] The value to set.
def city=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.city_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def city_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_city
# end
# @return [Boolean] true if the +city+ element is present on the page
def city?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +select :state+
# @return [String] The text content or value of +state+
def state
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.state_element).to exist
# end
# @return [Watir::Select] The raw +Select+ element
def state_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_state
# end
# @return [Boolean] true if the +state+ element is present on the page
def state?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :zip_code+
# @return [String] The text content or value of +zip_code+
def zip_code
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of zip_code
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.zip_code = 'value'
# end
# @param value [String] The value to set.
def zip_code=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.zip_code_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def zip_code_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_zip_code
# end
# @return [Boolean] true if the +zip_code+ element is present on the page
def zip_code?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +button :continue_to_payment+
# Clicks +continue_to_payment+
def continue_to_payment
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.continue_to_payment_element).to exist
# end
# @return [Watir::Button] The raw +Button+ element
def continue_to_payment_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_continue_to_payment
# end
# @return [Boolean] true if the +continue_to_payment+ element is present on the page
def continue_to_payment?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +iframe :payment_form+
# @return [String] The text content or value of +payment_form+
def payment_form
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.payment_form_element).to exist
# end
# @return [Watir::Iframe] The raw +Iframe+ element
def payment_form_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_payment_form
# end
# @return [Boolean] true if the +payment_form+ element is present on the page
def payment_form?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :name_on_card+
# @return [String] The text content or value of +name_on_card+
def name_on_card
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of name_on_card
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.name_on_card = 'value'
# end
# @param value [String] The value to set.
def name_on_card=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.name_on_card_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def name_on_card_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_name_on_card
# end
# @return [Boolean] true if the +name_on_card+ element is present on the page
def name_on_card?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :card_number+
# @return [String] The text content or value of +card_number+
def card_number
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of card_number
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.card_number = 'value'
# end
# @param value [String] The value to set.
def card_number=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.card_number_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def card_number_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_card_number
# end
# @return [Boolean] true if the +card_number+ element is present on the page
def card_number?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +select :expiration_month+
# @return [String] The text content or value of +expiration_month+
def expiration_month
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.expiration_month_element).to exist
# end
# @return [Watir::Select] The raw +Select+ element
def expiration_month_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_expiration_month
# end
# @return [Boolean] true if the +expiration_month+ element is present on the page
def expiration_month?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +select :expiration_year+
# @return [String] The text content or value of +expiration_year+
def expiration_year
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.expiration_year_element).to exist
# end
# @return [Watir::Select] The raw +Select+ element
def expiration_year_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_expiration_year
# end
# @return [Boolean] true if the +expiration_year+ element is present on the page
def expiration_year?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +text_field :cvv+
# @return [String] The text content or value of +cvv+
def cvv
# This is a stub, used for indexing. The method is dynamically generated.
end
# Set the value of cvv
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# new.cvv = 'value'
# end
# @param value [String] The value to set.
def cvv=(value)
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.cvv_element).to exist
# end
# @return [Watir::TextField] The raw +TextField+ element
def cvv_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_cvv
# end
# @return [Boolean] true if the +cvv+ element is present on the page
def cvv?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +link :review_your_order+
# Clicks +review_your_order+
def review_your_order
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.review_your_order_element).to exist
# end
# @return [Watir::Link] The raw +Link+ element
def review_your_order_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_review_your_order
# end
# @return [Boolean] true if the +review_your_order+ element is present on the page
def review_your_order?
# This is a stub, used for indexing. The method is dynamically generated.
end
# @note Defined as +button :confirm_purchase+
# Clicks +confirm_purchase+
def confirm_purchase
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new.confirm_purchase_element).to exist
# end
# @return [Watir::Button] The raw +Button+ element
def confirm_purchase_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Subscriptions::New.perform do |new|
# expect(new).to be_confirm_purchase
# end
# @return [Boolean] true if the +confirm_purchase+ element is present on the page
def confirm_purchase?
# This is a stub, used for indexing. The method is dynamically generated.
end
end
end
end
end

View File

@ -8,6 +8,8 @@ require_relative '../lib/gitlab'
require_relative '../lib/gitlab/utils'
require_relative '../config/initializers/0_inject_enterprise_edition_module'
require_relative 'lib/gitlab'
require 'chemlab'
module QA

View File

@ -1,13 +0,0 @@
# frozen_string_literal: true
module QA
module Page
module Group
module Settings
class Billing < Chemlab::Page
link :start_your_free_trial
end
end
end
end
end

View File

@ -25,6 +25,7 @@ module Matchers
@duration = options[:duration]
@attempts = options[:attempts]
@interval = options[:interval]
@reload_page = options[:reload_page]
end
def supports_block_expectations?
@ -59,7 +60,8 @@ module Matchers
QA::Support::Retrier.retry_until(
max_attempts: @attempts,
max_duration: @duration,
sleep_interval: @interval || 0.5
sleep_interval: @interval || 0.5,
reload_page: @reload_page
) do
QA::Runtime::Logger.debug("evaluating expectation, attempt: #{attempt += 1}")

View File

@ -32,7 +32,7 @@
#
# field :some_field,
# GraphQL::Types::String,
# description: "A thorough and compelling description."
# description: "Thorough and compelling description."
# end
#
# class GoodEnum
@ -43,8 +43,10 @@ module RuboCop
module Cop
module Graphql
class Descriptions < RuboCop::Cop::Cop
MSG_NO_DESCRIPTION = 'Please add a `description` property.'
MSG_NO_PERIOD = '`description` strings must end with a `.`.'
MSG_STYLE_GUIDE_LINK = 'See the description style guide: https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#description-style-guide'
MSG_NO_DESCRIPTION = "Please add a `description` property. #{MSG_STYLE_GUIDE_LINK}"
MSG_NO_PERIOD = "`description` strings must end with a `.`. #{MSG_STYLE_GUIDE_LINK}"
MSG_BAD_START = "`description` strings should not start with \"A...\" or \"The...\". #{MSG_STYLE_GUIDE_LINK}"
def_node_matcher :graphql_describable?, <<~PATTERN
(send nil? {:field :argument :value} ...)
@ -75,6 +77,7 @@ module RuboCop
return add_offense(node, location: :expression, message: MSG_NO_DESCRIPTION) unless description
add_offense(node, location: :expression, message: MSG_NO_PERIOD) if no_period?(description)
add_offense(node, location: :expression, message: MSG_BAD_START) if bad_start?(description)
end
# Autocorrect missing periods at end of description.
@ -100,12 +103,19 @@ module RuboCop
end
def no_period?(description)
# Test that the description node is a `:str` (as opposed to
# a `#copy_field_description` call) before checking.
description.type == :str && !description.value.strip.end_with?('.')
string?(description) && !description.value.strip.end_with?('.')
end
# Returns a Parser::Source::Range that ends just before the final String delimiter.
def bad_start?(description)
string?(description) && description.value.strip.downcase.start_with?('a ', 'the ')
end
# Returns true if `description` node is a `:str` (as opposed to a `#copy_field_description` call)
def string?(description)
description.type == :str
end
# Returns a `Parser::Source::Range` that ends just before the final `String` delimiter.
def before_end_quote(string)
return string.source_range.adjust(end_pos: -1) unless string.heredoc?

View File

@ -179,7 +179,7 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do
expect(response).to render_template('dashboard/projects/index')
expect(response.body).to include(
"pushed to project",
"uploaded design #{design.to_reference}",
"added design #{design.to_reference}",
"created wiki page #{wiki_page.title}",
"joined project #{project.full_name}",
"closed issue #{issue.to_reference}"

View File

@ -86,18 +86,5 @@ RSpec.describe JiraConnect::AppDescriptorController do
)
)
end
context 'when the jira_connect_create_branch feature is disabled' do
before do
stub_feature_flags(jira_connect_create_branch: false)
end
it 'does not include the create branch action' do
get :show
expect(response).to have_gitlab_http_status(:ok)
expect(descriptor[:modules][:jiraDevelopmentTool][:actions]).not_to include(:createBranch)
end
end
end
end

View File

@ -34,18 +34,6 @@ RSpec.describe JiraConnect::BranchesController do
expect(response).to be_successful
expect(assigns(:new_branch_data)).to include('initial_branch_name': nil)
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(jira_connect_create_branch: false)
end
it 'renders a 404 error' do
get :new
expect(response).to be_not_found
end
end
end
context 'when not logged in' do

View File

@ -194,6 +194,29 @@ RSpec.describe 'Dashboard Projects' do
end
end
describe 'with topics' do
context 'when project has topics' do
before do
project.update_attribute(:topic_list, 'topic1')
end
it 'shows project topics if exist' do
visit dashboard_projects_path
expect(page).to have_selector('[data-testid="project_topic_list"]')
expect(page).to have_link('topic1', href: explore_projects_path(topic: 'topic1'))
end
end
context 'when project does not have topics' do
it 'does not show project topics' do
visit dashboard_projects_path
expect(page).not_to have_selector('[data-testid="project_topic_list"]')
end
end
end
context 'last push widget', :use_clean_rails_memory_store_caching do
before do
event = create(:push_event, project: project, author: user)

View File

@ -34,26 +34,26 @@ RSpec.describe 'Projects > Activity > User sees design Activity', :js do
visit activity_project_path(project)
expect(page).to have_content('joined project')
expect(page).to have_content(design_activity(uploader, 'uploaded'))
expect(page).to have_content(design_activity(editor, 'revised'))
expect(page).to have_content(design_activity(deleter, 'deleted'))
expect(page).to have_content(design_activity(uploader, 'added'))
expect(page).to have_content(design_activity(editor, 'updated'))
expect(page).to have_content(design_activity(deleter, 'removed'))
end
it 'allows filtering out the design events', :aggregate_failures do
visit activity_project_path(project, event_filter: EventFilter::ISSUE)
expect(page).not_to have_content(design_activity(uploader, 'uploaded'))
expect(page).not_to have_content(design_activity(editor, 'revised'))
expect(page).not_to have_content(design_activity(deleter, 'deleted'))
expect(page).not_to have_content(design_activity(uploader, 'added'))
expect(page).not_to have_content(design_activity(editor, 'updated'))
expect(page).not_to have_content(design_activity(deleter, 'removed'))
end
it 'allows filtering in the design events', :aggregate_failures do
visit activity_project_path(project, event_filter: EventFilter::DESIGNS)
expect(page).not_to have_content('joined project')
expect(page).to have_content(design_activity(uploader, 'uploaded'))
expect(page).to have_content(design_activity(editor, 'revised'))
expect(page).to have_content(design_activity(deleter, 'deleted'))
expect(page).to have_content(design_activity(uploader, 'added'))
expect(page).to have_content(design_activity(editor, 'updated'))
expect(page).to have_content(design_activity(deleter, 'removed'))
end
end

View File

@ -16,7 +16,7 @@ RSpec.describe 'Projects > Show > Schema Markup' do
expect(page).to have_selector('[itemprop="identifier"]', text: "Project ID: #{project.id}")
expect(page).to have_selector('[itemprop="description"]', text: project.description)
expect(page).to have_selector('[itemprop="license"]', text: project.repository.license.name)
expect(find_all('[itemprop="keywords"]').map(&:text)).to match_array(project.topic_list.map(&:capitalize))
expect(find_all('[itemprop="keywords"]').map(&:text)).to match_array(project.topic_list)
expect(page).to have_selector('[itemprop="about"]')
end
end

View File

@ -132,8 +132,8 @@ RSpec.describe 'Project' do
visit path
expect(page).to have_css('.home-panel-topic-list')
expect(page).to have_link('Topic1', href: explore_projects_path(topic: 'topic1'))
expect(page).to have_selector('[data-testid="project_topic_list"]')
expect(page).to have_link('topic1', href: explore_projects_path(topic: 'topic1'))
end
it 'shows up to 3 project topics' do
@ -141,10 +141,10 @@ RSpec.describe 'Project' do
visit path
expect(page).to have_css('.home-panel-topic-list')
expect(page).to have_link('Topic1', href: explore_projects_path(topic: 'topic1'))
expect(page).to have_link('Topic2', href: explore_projects_path(topic: 'topic2'))
expect(page).to have_link('Topic3', href: explore_projects_path(topic: 'topic3'))
expect(page).to have_selector('[data-testid="project_topic_list"]')
expect(page).to have_link('topic1', href: explore_projects_path(topic: 'topic1'))
expect(page).to have_link('topic2', href: explore_projects_path(topic: 'topic2'))
expect(page).to have_link('topic3', href: explore_projects_path(topic: 'topic3'))
expect(page).to have_content('+ 1 more')
end
end

View File

@ -1,6 +1,5 @@
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import LockButton from 'ee_component/repository/components/lock_button.vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import BlobButtonGroup from '~/repository/components/blob_button_group.vue';
import DeleteBlobModal from '~/repository/components/delete_blob_modal.vue';
@ -19,7 +18,6 @@ const DEFAULT_PROPS = {
};
const DEFAULT_INJECT = {
glFeatures: { fileLocks: true },
targetBranch: 'master',
originalBranch: 'master',
};
@ -49,7 +47,6 @@ describe('BlobButtonGroup component', () => {
const findDeleteBlobModal = () => wrapper.findComponent(DeleteBlobModal);
const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
const findReplaceButton = () => wrapper.find('[data-testid="replace"]');
const findLockButton = () => wrapper.findComponent(LockButton);
it('renders component', () => {
createComponent();
@ -67,18 +64,6 @@ describe('BlobButtonGroup component', () => {
createComponent();
});
it('renders the lock button', () => {
expect(findLockButton().exists()).toBe(true);
expect(findLockButton().props()).toMatchObject({
canLock: true,
isLocked: false,
name: 'some name',
path: 'some/path',
projectPath: 'some/project/path',
});
});
it('renders both the replace and delete button', () => {
expect(wrapper.findAll(GlButton)).toHaveLength(2);
});

View File

@ -3,8 +3,14 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
let(:load_balancer) { Gitlab::Database::LoadBalancing::LoadBalancer.new([]) }
let(:service) do
described_class.new(nameserver: 'localhost', port: 8600, record: 'foo')
described_class.new(
nameserver: 'localhost',
port: 8600,
record: 'foo',
load_balancer: load_balancer
)
end
before do
@ -18,7 +24,15 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
describe '#initialize' do
describe ':record_type' do
subject { described_class.new(nameserver: 'localhost', port: 8600, record: 'foo', record_type: record_type) }
subject do
described_class.new(
nameserver: 'localhost',
port: 8600,
record: 'foo',
record_type: record_type,
load_balancer: load_balancer
)
end
context 'with a supported type' do
let(:record_type) { 'SRV' }
@ -162,7 +176,16 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
end
describe '#addresses_from_dns' do
let(:service) { described_class.new(nameserver: 'localhost', port: 8600, record: 'foo', record_type: record_type) }
let(:service) do
described_class.new(
nameserver: 'localhost',
port: 8600,
record: 'foo',
record_type: record_type,
load_balancer: load_balancer
)
end
let(:packet) { double(:packet, answer: [res1, res2]) }
before do
@ -234,13 +257,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
end
describe '#addresses_from_load_balancer' do
let(:load_balancer) do
Gitlab::Database::LoadBalancing::LoadBalancer.new(%w[b a])
end
it 'returns the ordered host names of the load balancer' do
load_balancer = Gitlab::Database::LoadBalancing::LoadBalancer.new(%w[b a])
allow(service)
.to receive(:load_balancer)
.and_return(load_balancer)
addresses = [
described_class::Address.new('a'),
described_class::Address.new('b')

View File

@ -982,9 +982,9 @@ RSpec.describe Event do
build(:design_event, trait).action_name
end
expect(created).to eq('uploaded')
expect(updated).to eq('revised')
expect(destroyed).to eq('deleted')
expect(created).to eq('added')
expect(updated).to eq('updated')
expect(destroyed).to eq('removed')
end
it 'handles correct push_action' do

View File

@ -12,7 +12,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ Please add a `description` property.
^^^^^^^^^^^^^^^ #{described_class::MSG_NO_DESCRIPTION}
GraphQL::Types::String,
null: false
end
@ -25,10 +25,38 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
^^^^^^^^^^^^^^^ #{described_class::MSG_NO_PERIOD}
GraphQL::Types::String,
null: false,
description: 'A descriptive description'
description: 'Description of a thing'
end
end
TYPE
end
it 'adds an offense when description begins with "A"' do
expect_offense(<<~TYPE)
module Types
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ #{described_class::MSG_BAD_START}
GraphQL::Types::String,
null: false,
description: 'A description of the thing.'
end
end
TYPE
end
it 'adds an offense when description begins with "The"' do
expect_offense(<<~TYPE)
module Types
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ #{described_class::MSG_BAD_START}
GraphQL::Types::String,
null: false,
description: 'The description of the thing.'
end
end
TYPE
@ -41,7 +69,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
field :a_thing,
GraphQL::Types::String,
null: false,
description: 'A descriptive description.'
description: 'Description of a thing.'
end
end
TYPE
@ -64,7 +92,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
argument :a_thing,
^^^^^^^^^^^^^^^^^^ Please add a `description` property.
^^^^^^^^^^^^^^^^^^ #{described_class::MSG_NO_DESCRIPTION}
GraphQL::Types::String,
null: false
end
@ -77,7 +105,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
argument :a_thing,
^^^^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
^^^^^^^^^^^^^^^^^^ #{described_class::MSG_NO_PERIOD}
GraphQL::Types::String,
null: false,
description: 'Behold! A description'
@ -86,6 +114,34 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
TYPE
end
it 'adds an offense when description begins with "A"' do
expect_offense(<<~TYPE)
module Types
class FakeType < BaseObject
argument :a_thing,
^^^^^^^^^^^^^^^^^^ #{described_class::MSG_BAD_START}
GraphQL::Types::String,
null: false,
description: 'A description.'
end
end
TYPE
end
it 'adds an offense when description begins with "The"' do
expect_offense(<<~TYPE)
module Types
class FakeType < BaseObject
argument :a_thing,
^^^^^^^^^^^^^^^^^^ #{described_class::MSG_BAD_START}
GraphQL::Types::String,
null: false,
description: 'The description.'
end
end
TYPE
end
it 'does not add an offense when description is correct' do
expect_no_offenses(<<~TYPE.strip)
module Types
@ -106,7 +162,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeEnum < BaseEnum
value 'FOO', value: 'foo'
^^^^^^^^^^^^^^^^^^^^^^^^^ Please add a `description` property.
^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG_NO_DESCRIPTION}
end
end
TYPE
@ -117,7 +173,29 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeEnum < BaseEnum
value 'FOO', value: 'foo', description: 'bar'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG_NO_PERIOD}
end
end
TYPE
end
it 'adds an offense when description begins with "The"' do
expect_offense(<<~TYPE.strip)
module Types
class FakeEnum < BaseEnum
value 'FOO', value: 'foo', description: 'The description.'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG_BAD_START}
end
end
TYPE
end
it 'adds an offense when description begins with "A"' do
expect_offense(<<~TYPE.strip)
module Types
class FakeEnum < BaseEnum
value 'FOO', value: 'foo', description: 'A description.'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG_BAD_START}
end
end
TYPE
@ -150,7 +228,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
^^^^^^^^^^^^^^^ #{described_class::MSG_NO_PERIOD}
GraphQL::Types::String,
null: false,
description: 'Behold! A description'
@ -175,7 +253,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
^^^^^^^^^^^^^^^ #{described_class::MSG_NO_PERIOD}
GraphQL::Types::String,
null: false,
description: <<~DESC

View File

@ -0,0 +1,80 @@
# frozen_string_literal: true
require 'rake_helper'
RSpec.describe 'gitlab:product_intelligence:activate_metrics', :silence_stdout do
def fake_metric(key_path, milestone: 'test_milestone', status: 'implemented')
Gitlab::Usage::MetricDefinition.new(key_path, { key_path: key_path, milestone: milestone, status: status })
end
before do
Rake.application.rake_require 'tasks/gitlab/product_intelligence'
stub_warn_user_is_not_gitlab
end
describe 'activate_metrics' do
it 'fails if the MILESTONE env var is not set' do
stub_env('MILESTONE' => nil)
expect { run_rake_task('gitlab:product_intelligence:activate_metrics') }.to raise_error(RuntimeError, 'Please supply the MILESTONE env var')
end
context 'with MILESTONE env var' do
subject do
updated_metrics = []
file = double('file')
allow(file).to receive(:<<) { |contents| updated_metrics << YAML.safe_load(contents) }
allow(File).to receive(:open).and_yield(file)
stub_env('MILESTONE' => 'test_milestone')
run_rake_task('gitlab:product_intelligence:activate_metrics')
updated_metrics
end
let(:metric_definitions) do
{
matching_metric: fake_metric('matching_metric'),
matching_metric2: fake_metric('matching_metric2'),
other_status_metric: fake_metric('other_status_metric', status: 'deprecated'),
other_milestone_metric: fake_metric('other_milestone_metric', milestone: 'other_milestone')
}
end
before do
allow(Gitlab::Usage::MetricDefinition).to receive(:definitions).and_return(metric_definitions)
end
context 'with metric matching status and milestone' do
it 'updates matching_metric yaml file' do
expect(subject).to eq([
{ 'key_path' => 'matching_metric', 'milestone' => 'test_milestone', 'status' => 'data_available' },
{ 'key_path' => 'matching_metric2', 'milestone' => 'test_milestone', 'status' => 'data_available' }
])
end
end
context 'without metrics definitions' do
let(:metric_definitions) { {} }
it 'runs successfully with no updates' do
expect(subject).to eq([])
end
end
context 'without matching metrics' do
let(:metric_definitions) do
{
other_status_metric: fake_metric('other_status_metric', status: 'deprecated'),
other_milestone_metric: fake_metric('other_milestone_metric', milestone: 'other_milestone')
}
end
it 'runs successfully with no updates' do
expect(subject).to eq([])
end
end
end
end
end