Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fbc7e1f503
commit
2ccb5c91c8
86 changed files with 466 additions and 443 deletions
|
@ -121,6 +121,11 @@ yarn-audit-dependency_scanning:
|
|||
- cd .. && tar -I "gzip --best" -cf gitlab.tgz gitlab/
|
||||
script:
|
||||
- DEBUG=* node /usr/src/app/cli.js analyze --format gitlab --manager ${PACKAGE_MANAGER} gitlab.tgz | tee ${CI_PROJECT_DIR}/gl-dependency-scanning-report.json
|
||||
after_script:
|
||||
- mkdir ~/.aws
|
||||
- '[[ -z "${AWS_SIEM_REPORT_INGESTION_CREDENTIALS_FILE}" ]] || mv "${AWS_SIEM_REPORT_INGESTION_CREDENTIALS_FILE}" ~/.aws/credentials'
|
||||
- npm install --no-save --ignore-scripts @aws-sdk/client-s3@3.49.0
|
||||
- scripts/ingest-reports-to-siem
|
||||
artifacts:
|
||||
paths:
|
||||
- gl-dependency-scanning-report.json
|
||||
|
|
|
@ -17,9 +17,6 @@ export default {
|
|||
revokePath: {
|
||||
default: '',
|
||||
},
|
||||
buttonClass: {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
modalId() {
|
||||
|
@ -38,10 +35,9 @@ export default {
|
|||
<div>
|
||||
<gl-button
|
||||
v-gl-modal="modalId"
|
||||
:class="buttonClass"
|
||||
category="primary"
|
||||
variant="danger"
|
||||
class="float-right"
|
||||
class="gl-float-right"
|
||||
data-testid="revoke-button"
|
||||
>{{ s__('DeployTokens|Revoke') }}</gl-button
|
||||
>
|
||||
|
|
|
@ -9,14 +9,13 @@ export default () => {
|
|||
}
|
||||
|
||||
return containers.forEach((el) => {
|
||||
const { token, revokePath, buttonClass } = el.dataset;
|
||||
const { token, revokePath } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
provide: {
|
||||
token: JSON.parse(token),
|
||||
revokePath,
|
||||
buttonClass,
|
||||
},
|
||||
render(h) {
|
||||
return h(RevokeButton);
|
||||
|
|
|
@ -83,17 +83,17 @@ export default {
|
|||
i18n: {
|
||||
sectionTitle: s__('JiraService|View Jira issues in GitLab'),
|
||||
sectionDescription: s__(
|
||||
'JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of Jira issues and view any issue as read-only.',
|
||||
'JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues.',
|
||||
),
|
||||
enableCheckboxLabel: s__('JiraService|Enable Jira issues'),
|
||||
enableCheckboxHelp: s__(
|
||||
'JiraService|Warning: All GitLab users that have access to this GitLab project are able to view all issues from the Jira project specified below.',
|
||||
'JiraService|Warning: All GitLab users with access to this GitLab project can view all issues from the Jira project you select.',
|
||||
),
|
||||
projectKeyLabel: s__('JiraService|Jira project key'),
|
||||
projectKeyPlaceholder: s__('JiraService|For example, AB'),
|
||||
requiredFieldFeedback: __('This field is required.'),
|
||||
issueTrackerConflictWarning: s__(
|
||||
'JiraService|Displaying Jira issues while leaving the GitLab issue functionality enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used.',
|
||||
'JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used.',
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -138,7 +138,7 @@ export default {
|
|||
label-for="service[trigger]"
|
||||
:description="
|
||||
s__(
|
||||
'Integrations|When you mention a Jira issue in a commit or merge request, GitLab creates a remote link and comment (if enabled).',
|
||||
'JiraService|When a Jira issue is mentioned in a commit or merge request, a remote link and comment (if enabled) will be created.',
|
||||
)
|
||||
"
|
||||
>
|
||||
|
|
|
@ -264,7 +264,7 @@ export default {
|
|||
<gl-button
|
||||
:disabled="submitDisabled"
|
||||
:loading="isLoading"
|
||||
variant="success"
|
||||
variant="confirm"
|
||||
data-qa-selector="invite_button"
|
||||
data-testid="invite-button"
|
||||
@click="submit"
|
||||
|
|
|
@ -135,6 +135,14 @@ export default {
|
|||
const canReopen = this.isClosed && this.canReopenIssue;
|
||||
return canClose || canReopen;
|
||||
},
|
||||
hasDesktopDropdown() {
|
||||
return (
|
||||
this.canCreateIssue || this.canPromoteToEpic || !this.isIssueAuthor || this.canReportSpam
|
||||
);
|
||||
},
|
||||
hasMobileDropdown() {
|
||||
return this.hasDesktopDropdown || this.showToggleIssueStateButton;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
eventHub.$on('toggle.issuable.state', this.toggleIssueState);
|
||||
|
@ -223,10 +231,12 @@ export default {
|
|||
<template>
|
||||
<div class="detail-page-header-actions gl-display-flex">
|
||||
<gl-dropdown
|
||||
v-if="hasMobileDropdown"
|
||||
class="gl-sm-display-none! w-100"
|
||||
block
|
||||
:text="dropdownText"
|
||||
data-qa-selector="issue_actions_dropdown"
|
||||
data-testid="mobile-dropdown"
|
||||
:loading="isToggleStateButtonLoading"
|
||||
>
|
||||
<gl-dropdown-item
|
||||
|
@ -276,11 +286,13 @@ export default {
|
|||
</gl-button>
|
||||
|
||||
<gl-dropdown
|
||||
v-if="hasDesktopDropdown"
|
||||
class="gl-display-none gl-sm-display-inline-flex! gl-ml-3"
|
||||
icon="ellipsis_v"
|
||||
category="tertiary"
|
||||
:text="dropdownText"
|
||||
:text-sr-only="true"
|
||||
data-testid="desktop-dropdown"
|
||||
no-caret
|
||||
right
|
||||
>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlSprintf, GlButton, GlButtonGroup } from '@gitlab/ui';
|
||||
import { GlSprintf, GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { mapGetters, mapState, mapActions } from 'vuex';
|
||||
import { __ } from '~/locale';
|
||||
import FileIcon from '~/vue_shared/components/file_icon.vue';
|
||||
|
@ -23,6 +23,7 @@ export default {
|
|||
GlButton,
|
||||
GlButtonGroup,
|
||||
GlSprintf,
|
||||
GlLoadingIcon,
|
||||
FileIcon,
|
||||
DiffFileEditor,
|
||||
InlineConflictLines,
|
||||
|
@ -72,9 +73,7 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div id="conflicts">
|
||||
<div v-if="isLoading" class="loading">
|
||||
<div class="spinner spinner-md"></div>
|
||||
</div>
|
||||
<gl-loading-icon v-if="isLoading" size="md" data-testid="loading-spinner" />
|
||||
<div v-if="hasError" class="nothing-here-block">
|
||||
{{ conflictsData.errorMessage }}
|
||||
</div>
|
||||
|
|
|
@ -69,9 +69,10 @@ export default {
|
|||
// If it's a brand new file, we don't want to fetch the content.
|
||||
// Then when the user commits the first time, the query would run
|
||||
// to get the initial file content, but we already have it in `lastCommitedContent`
|
||||
// so we skip the loading altogether.
|
||||
skip({ isNewCiConfigFile, lastCommittedContent }) {
|
||||
return isNewCiConfigFile || lastCommittedContent;
|
||||
// so we skip the loading altogether. We also wait for the currentBranch
|
||||
// to have been fetched
|
||||
skip() {
|
||||
return this.shouldSkipBlobContentQuery;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
|
@ -128,8 +129,8 @@ export default {
|
|||
},
|
||||
ciConfigData: {
|
||||
query: getCiConfigData,
|
||||
skip({ currentCiFileContent }) {
|
||||
return !currentCiFileContent;
|
||||
skip() {
|
||||
return this.shouldSkipCiConfigQuery;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
|
@ -174,6 +175,9 @@ export default {
|
|||
},
|
||||
commitSha: {
|
||||
query: getLatestCommitShaQuery,
|
||||
skip({ currentBranch }) {
|
||||
return !currentBranch;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
projectPath: this.projectFullPath,
|
||||
|
@ -181,7 +185,7 @@ export default {
|
|||
};
|
||||
},
|
||||
update(data) {
|
||||
const latestCommitSha = data.project?.repository?.tree?.lastCommit?.sha;
|
||||
const latestCommitSha = data?.project?.repository?.tree?.lastCommit?.sha;
|
||||
|
||||
if (this.isFetchingCommitSha && latestCommitSha === this.commitSha) {
|
||||
this.$apollo.queries.commitSha.startPolling(COMMIT_SHA_POLL_INTERVAL);
|
||||
|
@ -192,6 +196,9 @@ export default {
|
|||
this.$apollo.queries.commitSha.stopPolling();
|
||||
return latestCommitSha;
|
||||
},
|
||||
error() {
|
||||
this.reportFailure(LOAD_FAILURE_UNKNOWN);
|
||||
},
|
||||
},
|
||||
currentBranch: {
|
||||
query: getCurrentBranch,
|
||||
|
@ -234,6 +241,12 @@ export default {
|
|||
isEmpty() {
|
||||
return this.currentCiFileContent === '';
|
||||
},
|
||||
shouldSkipBlobContentQuery() {
|
||||
return this.isNewCiConfigFile || this.lastCommittedContent || !this.currentBranch;
|
||||
},
|
||||
shouldSkipCiConfigQuery() {
|
||||
return !this.currentCiFileContent || !this.commitSha;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
resetModal: {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { convertToGraphQLId } from '~/graphql_shared/utils';
|
|||
import RunnerHeader from '../components/runner_header.vue';
|
||||
import RunnerUpdateForm from '../components/runner_update_form.vue';
|
||||
import { I18N_FETCH_ERROR } from '../constants';
|
||||
import getRunnerQuery from '../graphql/get_runner.query.graphql';
|
||||
import runnerQuery from '../graphql/details/runner.query.graphql';
|
||||
import { captureException } from '../sentry_utils';
|
||||
|
||||
export default {
|
||||
|
@ -27,7 +27,7 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
runner: {
|
||||
query: getRunnerQuery,
|
||||
query: runnerQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: convertToGraphQLId(TYPE_CI_RUNNER, this.runnerId),
|
||||
|
|
|
@ -8,7 +8,7 @@ import RunnerPauseButton from '../components/runner_pause_button.vue';
|
|||
import RunnerHeader from '../components/runner_header.vue';
|
||||
import RunnerDetails from '../components/runner_details.vue';
|
||||
import { I18N_FETCH_ERROR } from '../constants';
|
||||
import getRunnerQuery from '../graphql/get_runner.query.graphql';
|
||||
import runnerQuery from '../graphql/details/runner.query.graphql';
|
||||
import { captureException } from '../sentry_utils';
|
||||
|
||||
export default {
|
||||
|
@ -35,7 +35,7 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
runner: {
|
||||
query: getRunnerQuery,
|
||||
query: runnerQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: convertToGraphQLId(TYPE_CI_RUNNER, this.runnerId),
|
||||
|
|
|
@ -26,8 +26,8 @@ import {
|
|||
STATUS_STALE,
|
||||
I18N_FETCH_ERROR,
|
||||
} from '../constants';
|
||||
import getRunnersQuery from '../graphql/get_runners.query.graphql';
|
||||
import getRunnersCountQuery from '../graphql/get_runners_count.query.graphql';
|
||||
import runnersAdminQuery from '../graphql/list/admin_runners.query.graphql';
|
||||
import runnersAdminCountQuery from '../graphql/list/admin_runners_count.query.graphql';
|
||||
import {
|
||||
fromUrlQueryToSearch,
|
||||
fromSearchToUrl,
|
||||
|
@ -36,7 +36,7 @@ import {
|
|||
import { captureException } from '../sentry_utils';
|
||||
|
||||
const runnersCountSmartQuery = {
|
||||
query: getRunnersCountQuery,
|
||||
query: runnersAdminCountQuery,
|
||||
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
|
||||
update(data) {
|
||||
return data?.runners?.count;
|
||||
|
@ -77,7 +77,7 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
runners: {
|
||||
query: getRunnersQuery,
|
||||
query: runnersAdminQuery,
|
||||
// Runners can be updated by users directly in this list.
|
||||
// A "cache and network" policy prevents outdated filtered
|
||||
// results.
|
||||
|
|
|
@ -4,7 +4,7 @@ import { createAlert } from '~/flash';
|
|||
import { TYPE_GROUP, TYPE_PROJECT } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { __, s__ } from '~/locale';
|
||||
import runnersRegistrationTokenResetMutation from '~/runner/graphql/runners_registration_token_reset.mutation.graphql';
|
||||
import runnersRegistrationTokenResetMutation from '~/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
|
||||
import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql';
|
||||
import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql';
|
||||
import { createAlert } from '~/flash';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlSkeletonLoading } from '@gitlab/ui';
|
||||
import { createAlert } from '~/flash';
|
||||
import getRunnerJobsQuery from '../graphql/get_runner_jobs.query.graphql';
|
||||
import runnerJobsQuery from '../graphql/details/runner_jobs.query.graphql';
|
||||
import { I18N_FETCH_ERROR, I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '../constants';
|
||||
import { captureException } from '../sentry_utils';
|
||||
import { getPaginationVariables } from '../utils';
|
||||
|
@ -34,7 +34,7 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
jobs: {
|
||||
query: getRunnerJobsQuery,
|
||||
query: runnerJobsQuery,
|
||||
variables() {
|
||||
return this.variables;
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import runnerToggleActiveMutation from '~/runner/graphql/runner_toggle_active.mutation.graphql';
|
||||
import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql';
|
||||
import { createAlert } from '~/flash';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { I18N_PAUSE, I18N_RESUME } from '../constants';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { GlSkeletonLoading } from '@gitlab/ui';
|
||||
import { sprintf, formatNumber } from '~/locale';
|
||||
import { createAlert } from '~/flash';
|
||||
import getRunnerProjectsQuery from '../graphql/get_runner_projects.query.graphql';
|
||||
import runnerProjectsQuery from '../graphql/details/runner_projects.query.graphql';
|
||||
import {
|
||||
I18N_ASSIGNED_PROJECTS,
|
||||
I18N_NONE,
|
||||
|
@ -41,7 +41,7 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
projects: {
|
||||
query: getRunnerProjectsQuery,
|
||||
query: runnerProjectsQuery,
|
||||
variables() {
|
||||
return this.variables;
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ import { createAlert, VARIANT_SUCCESS } from '~/flash';
|
|||
import { __ } from '~/locale';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
|
||||
import runnerUpdateMutation from '../graphql/runner_update.mutation.graphql';
|
||||
import runnerUpdateMutation from '../graphql/details/runner_update.mutation.graphql';
|
||||
|
||||
export default {
|
||||
name: 'RunnerUpdateForm',
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#import "ee_else_ce/runner/graphql/runner_details.fragment.graphql"
|
||||
#import "ee_else_ce/runner/graphql/details/runner_details.fragment.graphql"
|
||||
|
||||
query getRunner($id: CiRunnerID!) {
|
||||
# We have an id in deeply nested fragment
|
||||
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
||||
runner(id: $id) {
|
||||
__typename
|
||||
...RunnerDetails
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
fragment RunnerDetailsShared on CiRunner {
|
||||
__typename
|
||||
id
|
||||
runnerType
|
||||
active
|
||||
|
@ -22,7 +23,7 @@ fragment RunnerDetailsShared on CiRunner {
|
|||
groups {
|
||||
# Only a single group can be loaded here, while projects
|
||||
# are loaded separately using the query with pagination
|
||||
# parameters `get_runner_projects.query.graphql`.
|
||||
# parameters `runner_projects.query.graphql`.
|
||||
nodes {
|
||||
id
|
||||
avatarUrl
|
|
@ -1,4 +1,4 @@
|
|||
#import "ee_else_ce/runner/graphql/runner_details.fragment.graphql"
|
||||
#import "ee_else_ce/runner/graphql/details/runner_details.fragment.graphql"
|
||||
|
||||
# Mutation for updates from the runner form, loads
|
||||
# attributes shown in the runner details.
|
|
@ -1,4 +1,4 @@
|
|||
#import "~/runner/graphql/runner_node.fragment.graphql"
|
||||
#import "~/runner/graphql/list/list_item.fragment.graphql"
|
||||
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
|
||||
|
||||
query getRunners(
|
||||
|
@ -24,7 +24,7 @@ query getRunners(
|
|||
sort: $sort
|
||||
) {
|
||||
nodes {
|
||||
...RunnerNode
|
||||
...ListItem
|
||||
adminUrl
|
||||
editAdminUrl
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#import "~/runner/graphql/runner_node.fragment.graphql"
|
||||
#import "~/runner/graphql/list/list_item.fragment.graphql"
|
||||
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
|
||||
|
||||
query getGroupRunners(
|
||||
|
@ -29,8 +29,7 @@ query getGroupRunners(
|
|||
webUrl
|
||||
editUrl
|
||||
node {
|
||||
__typename
|
||||
...RunnerNode
|
||||
...ListItem
|
||||
}
|
||||
}
|
||||
pageInfo {
|
|
@ -1,4 +1,4 @@
|
|||
fragment RunnerNode on CiRunner {
|
||||
fragment ListItem on CiRunner {
|
||||
__typename
|
||||
id
|
||||
description
|
|
@ -24,8 +24,8 @@ import {
|
|||
STATUS_OFFLINE,
|
||||
STATUS_STALE,
|
||||
} from '../constants';
|
||||
import getGroupRunnersQuery from '../graphql/get_group_runners.query.graphql';
|
||||
import getGroupRunnersCountQuery from '../graphql/get_group_runners_count.query.graphql';
|
||||
import groupRunnersQuery from '../graphql/list/group_runners.query.graphql';
|
||||
import groupRunnersCountQuery from '../graphql/list/group_runners_count.query.graphql';
|
||||
import {
|
||||
fromUrlQueryToSearch,
|
||||
fromSearchToUrl,
|
||||
|
@ -34,7 +34,7 @@ import {
|
|||
import { captureException } from '../sentry_utils';
|
||||
|
||||
const runnersCountSmartQuery = {
|
||||
query: getGroupRunnersCountQuery,
|
||||
query: groupRunnersCountQuery,
|
||||
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
|
||||
update(data) {
|
||||
return data?.group?.runners?.count;
|
||||
|
@ -84,7 +84,7 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
runners: {
|
||||
query: getGroupRunnersQuery,
|
||||
query: groupRunnersQuery,
|
||||
// Runners can be updated by users directly in this list.
|
||||
// A "cache and network" policy prevents outdated filtered
|
||||
// results.
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
class Projects::ClusterAgentsController < Projects::ApplicationController
|
||||
before_action :authorize_can_read_cluster_agent!
|
||||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:cluster_vulnerabilities, project, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
feature_category :kubernetes_management
|
||||
|
||||
def show
|
||||
|
|
|
@ -3,20 +3,6 @@
|
|||
class ApplicationExperiment < Gitlab::Experiment
|
||||
control { nil } # provide a default control for anonymous experiments
|
||||
|
||||
def publish(_result = nil)
|
||||
super
|
||||
|
||||
publish_to_client
|
||||
end
|
||||
|
||||
def publish_to_client
|
||||
return unless should_track?
|
||||
|
||||
Gon.push({ experiment: { name => signature } }, true)
|
||||
rescue NoMethodError
|
||||
# means we're not in the request cycle, and can't add to Gon. Log a warning maybe?
|
||||
end
|
||||
|
||||
def publish_to_database
|
||||
ActiveSupport::Deprecation.warn('publish_to_database is deprecated and should not be used for reporting anymore')
|
||||
|
||||
|
|
|
@ -16,4 +16,11 @@ module DeployTokensHelper
|
|||
Gitlab.config.packages.enabled &&
|
||||
can?(current_user, :read_package, group_or_project)
|
||||
end
|
||||
|
||||
def deploy_token_revoke_button_data(token:, group_or_project:)
|
||||
{
|
||||
token: token.to_json(only: [:id, :name]),
|
||||
revoke_path: revoke_deploy_token_path(group_or_project, token)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,8 +111,8 @@ module Integrations
|
|||
end
|
||||
|
||||
def help
|
||||
jira_doc_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_url('integration/jira/index.html') }
|
||||
s_("JiraService|You must configure Jira before enabling this integration. For more details, read the %{jira_doc_link_start}Jira integration documentation%{link_end}.") % { jira_doc_link_start: jira_doc_link_start, link_end: '</a>'.html_safe }
|
||||
jira_doc_link_start = '<a href="%{url}">'.html_safe % { url: help_page_url('integration/jira/index.html') }
|
||||
s_("JiraService|You must configure Jira before enabling this integration. %{jira_doc_link_start}Learn more.%{link_end}") % { jira_doc_link_start: jira_doc_link_start, link_end: '</a>'.html_safe }
|
||||
end
|
||||
|
||||
def title
|
||||
|
|
|
@ -40,12 +40,7 @@ class Namespace
|
|||
SQL
|
||||
|
||||
Namespace.transaction do
|
||||
if Feature.enabled?(:for_no_key_update_lock, default_enabled: :yaml)
|
||||
@root.lock!("FOR NO KEY UPDATE")
|
||||
else
|
||||
@root.lock!
|
||||
end
|
||||
|
||||
@root.lock!("FOR NO KEY UPDATE")
|
||||
Namespace.connection.exec_query(sql)
|
||||
end
|
||||
rescue ActiveRecord::Deadlocked
|
||||
|
|
|
@ -44,22 +44,15 @@ module Namespaces
|
|||
included do
|
||||
before_update :lock_both_roots, if: -> { sync_traversal_ids? && parent_id_changed? }
|
||||
after_update :sync_traversal_ids, if: -> { sync_traversal_ids? && saved_change_to_parent_id? }
|
||||
# sync traversal_ids on namespace create, which can happen quite early within a transaction, thus keeping the lock on root namespace record
|
||||
# for a relatively long time, e.g. creating the project namespace when a project is being created.
|
||||
after_create :sync_traversal_ids, if: -> { sync_traversal_ids? && !sync_traversal_ids_before_commit? }
|
||||
# This uses rails internal before_commit API to sync traversal_ids on namespace create, right before transaction is committed.
|
||||
# This helps reduce the time during which the root namespace record is locked to ensure updated traversal_ids are valid
|
||||
before_commit :sync_traversal_ids, on: [:create], if: -> { sync_traversal_ids? && sync_traversal_ids_before_commit? }
|
||||
before_commit :sync_traversal_ids, on: [:create], if: -> { sync_traversal_ids? }
|
||||
end
|
||||
|
||||
def sync_traversal_ids?
|
||||
Feature.enabled?(:sync_traversal_ids, root_ancestor, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
def sync_traversal_ids_before_commit?
|
||||
Feature.enabled?(:sync_traversal_ids_before_commit, root_ancestor, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
def use_traversal_ids?
|
||||
return false unless Feature.enabled?(:use_traversal_ids, default_enabled: :yaml)
|
||||
|
||||
|
|
|
@ -22,15 +22,15 @@
|
|||
= f.label :eks_account_id, _('Account ID'), class: 'label-bold'
|
||||
= f.text_field :eks_account_id, class: 'form-control gl-form-input'
|
||||
.form-group
|
||||
= f.label :eks_access_key_id, _('Access key ID'), class: 'label-bold'
|
||||
= f.label :eks_access_key_id, _('AWS access key ID (Optional)'), class: 'label-bold'
|
||||
= f.text_field :eks_access_key_id, class: 'form-control gl-form-input'
|
||||
.form-text.text-muted
|
||||
= _('AWS Access Key. Only required if not using role instance credentials')
|
||||
= _('Only required if not using role instance credentials.')
|
||||
|
||||
.form-group
|
||||
= f.label :eks_secret_access_key, _('Secret access key'), class: 'label-bold'
|
||||
= f.label :eks_secret_access_key, _('AWS secret access key (Optional)'), class: 'label-bold'
|
||||
= f.password_field :eks_secret_access_key, autocomplete: 'off', class: 'form-control gl-form-input'
|
||||
.form-text.text-muted
|
||||
= _('AWS Secret Access Key. Only required if not using role instance credentials')
|
||||
= _('Only required if not using role instance credentials.')
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
- link_end = "#{sprite_icon('external-link', size: 12, css_class: 'ml-1 vertical-align-center')}</a>".html_safe
|
||||
= s_('SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance\'s code views and merge requests.').html_safe % { link_start: link_start, link_end: link_end }
|
||||
%span
|
||||
= link_to s_('SourcegraphAdmin|More information'), help_page_path('integration/sourcegraph.md'), target: '_blank', rel: 'noopener noreferrer'
|
||||
= link_to s_('SourcegraphAdmin|Learn more.'), help_page_path('integration/sourcegraph.md'), target: '_blank', rel: 'noopener noreferrer'
|
||||
|
||||
|
||||
.settings-content
|
||||
|
@ -29,10 +29,10 @@
|
|||
= f.check_box :sourcegraph_public_only, class: 'form-check-input'
|
||||
= f.label :sourcegraph_public_only, s_('SourcegraphAdmin|Block on private and internal projects'), class: 'form-check-label'
|
||||
.form-text.text-muted
|
||||
= s_('SourcegraphAdmin|If checked, only public projects will have code intelligence and communicate with Sourcegraph.')
|
||||
= s_('SourcegraphAdmin|Only public projects have code intelligence enabled and communicate with Sourcegraph.')
|
||||
.form-group
|
||||
= f.label :sourcegraph_url, s_('SourcegraphAdmin|Sourcegraph URL'), class: 'label-bold'
|
||||
= f.text_field :sourcegraph_url, class: 'form-control gl-form-input', placeholder: s_('SourcegraphAdmin|e.g. https://sourcegraph.example.com')
|
||||
= f.text_field :sourcegraph_url, class: 'form-control gl-form-input', placeholder: s_('SourcegraphAdmin|https://sourcegraph.example.com')
|
||||
.form-text.text-muted
|
||||
= s_('SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can read your GitLab projects.')
|
||||
= f.submit s_('SourcegraphAdmin|Save changes'), class: 'gl-button btn btn-confirm'
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
.gl-w-half.gl-xs-w-full
|
||||
.gl-display-flex.gl-flex-wrap.gl-justify-content-end.gl-mb-3
|
||||
.js-invite-group-trigger{ data: { classes: 'gl-mt-3 gl-sm-w-auto gl-w-full', display_text: _('Invite a group') } }
|
||||
.js-invite-members-trigger{ data: { variant: 'success',
|
||||
.js-invite-members-trigger{ data: { variant: 'confirm',
|
||||
classes: 'gl-mt-3 gl-sm-w-auto gl-w-full gl-sm-ml-3',
|
||||
trigger_source: 'group-members-page',
|
||||
display_text: _('Invite members') } }
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
.js-invite-group-trigger{ data: { classes: 'gl-mt-3 gl-sm-w-auto gl-w-full gl-sm-ml-3', display_text: _('Invite a group') } }
|
||||
= render 'projects/invite_groups_modal', project: @project
|
||||
- if can_admin_project_member?(@project)
|
||||
.js-invite-members-trigger{ data: { variant: 'success',
|
||||
.js-invite-members-trigger{ data: { variant: 'confirm',
|
||||
classes: 'gl-mt-3 gl-sm-w-auto gl-w-full gl-sm-ml-3',
|
||||
trigger_source: 'project-members-page',
|
||||
display_text: _('Invite members') } }
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
%span.token-never-expires-label= _('Never')
|
||||
%td= token.scopes.present? ? token.scopes.join(', ') : _('no scopes selected')
|
||||
%td
|
||||
.js-deploy-token-revoke-button{ data: { button_class: 'float-right', token: token.to_json, revoke_path: revoke_deploy_token_path(group_or_project, token) } }
|
||||
.js-deploy-token-revoke-button{ data: deploy_token_revoke_button_data(token: token, group_or_project: group_or_project) }
|
||||
|
||||
- else
|
||||
.settings-message.text-center
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: cluster_vulnerabilities
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73321
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343917
|
||||
milestone: '14.5'
|
||||
type: development
|
||||
group: group::container security
|
||||
default_enabled: true
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: for_no_key_update_lock
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81239
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353619
|
||||
milestone: '14.9'
|
||||
type: development
|
||||
group: group::workspaces
|
||||
default_enabled: false
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: sync_traversal_ids_before_commit
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79964
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/352499
|
||||
group: group::workspace
|
||||
type: development
|
||||
default_enabled: false
|
||||
milestone: '14.8'
|
|
@ -317,7 +317,7 @@ of tracking an event in Ruby would be:
|
|||
experiment(:pill_color, actor: current_user).track(:clicked)
|
||||
```
|
||||
|
||||
When you run an experiment with any of the examples so far, an `:assigned` event
|
||||
When you run an experiment with any of the examples so far, an `:assignment` event
|
||||
is tracked automatically by default. All events that are tracked from an
|
||||
experiment have a special
|
||||
[experiment context](https://gitlab.com/gitlab-org/iglu/-/blob/master/public/schemas/com.gitlab/gitlab_experiment/jsonschema/1-0-3)
|
||||
|
|
|
@ -50,7 +50,7 @@ To configure your project:
|
|||
If you enable Jira issues with this setting, all users with access to this GitLab project
|
||||
can view all issues from the specified Jira project.
|
||||
|
||||
1. To enable [issue creation for vulnerabilities](../../user/application_security/vulnerabilities/index.md#create-a-jira-issue-for-a-vulnerability), select **Enable Jira issues creation from vulnerabilities**.
|
||||
1. To enable [issue creation for vulnerabilities](../../user/application_security/vulnerabilities/index.md#create-a-jira-issue-for-a-vulnerability), select **Enable Jira issue creation from vulnerabilities**.
|
||||
1. Select the **Jira issue type**. If the dropdown is empty, select refresh (**{retry}**) and try again.
|
||||
1. To verify the Jira connection is working, select **Test settings**.
|
||||
1. Select **Save changes**.
|
||||
|
|
|
@ -80,7 +80,7 @@ The issue is then opened so you can take further action.
|
|||
Prerequisites:
|
||||
|
||||
- [Enable Jira integration](../../../integration/jira/index.md).
|
||||
The **Enable Jira issues creation from vulnerabilities** option must be selected as part of the configuration.
|
||||
The **Enable Jira issue creation from vulnerabilities** option must be selected as part of the configuration.
|
||||
- Each user must have a personal Jira user account with permission to create issues in the target project.
|
||||
|
||||
To create a Jira issue for a vulnerability:
|
||||
|
|
|
@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Container vulnerability scanning **(ULTIMATE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6346) in GitLab 14.8 [with a flag](../../../administration/feature_flags.md) named `cluster_vulnerabilities`. Enabled by default.
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6346) in GitLab 14.8.
|
||||
|
||||
To view cluster vulnerabilities, you can view the [vulnerability report](../../application_security/vulnerabilities/index.md).
|
||||
You can also configure your agent so the vulnerabilities are displayed with other agent information in GitLab.
|
||||
|
|
|
@ -67,15 +67,15 @@ Features not found in standard Markdown:
|
|||
|
||||
Features [extended from standard Markdown](#features-extended-from-standard-markdown):
|
||||
|
||||
| Standard Markdown | Extended Markdown in GitLab |
|
||||
| ------------------------------------- | ------------------------- |
|
||||
| [blockquotes](#blockquotes) | [multi-line blockquotes](#multiline-blockquote) |
|
||||
| [code blocks](#code-spans-and-blocks) | [colored code and syntax highlighting](#colored-code-and-syntax-highlighting) |
|
||||
| [emphasis](#emphasis) | [multiple underscores in words](#multiple-underscores-in-words-and-mid-word-emphasis)
|
||||
| [headers](#headers) | [linkable Header IDs](#header-ids-and-links) |
|
||||
| [images](#images) | [embedded videos](#videos) and [audio](#audio) |
|
||||
| [line breaks](#line-breaks) | [more line break control](#newlines) |
|
||||
| [links](#links) | [automatically linking URLs](#url-auto-linking) |
|
||||
| Standard Markdown | Extended Markdown in GitLab |
|
||||
|---------------------------------------|---------------------------------------------------------------------------------------|
|
||||
| [blockquotes](#blockquotes) | [multi-line blockquotes](#multiline-blockquote) |
|
||||
| [code blocks](#code-spans-and-blocks) | [colored code and syntax highlighting](#colored-code-and-syntax-highlighting) |
|
||||
| [emphasis](#emphasis) | [multiple underscores in words](#multiple-underscores-in-words-and-mid-word-emphasis) |
|
||||
| [headers](#headers) | [linkable Header IDs](#header-ids-and-links) |
|
||||
| [images](#images) | [embedded videos](#videos) and [audio](#audio) |
|
||||
| [line breaks](#line-breaks) | [more line break control](#newlines) |
|
||||
| [links](#links) | [automatically linking URLs](#url-auto-linking) |
|
||||
|
||||
## Features not found in standard Markdown
|
||||
|
||||
|
@ -262,7 +262,7 @@ The following delimiters are supported:
|
|||
---
|
||||
title: About Front Matter
|
||||
example:
|
||||
language: yaml
|
||||
language: yaml
|
||||
---
|
||||
```
|
||||
|
||||
|
@ -515,31 +515,31 @@ version to reference other projects from the same namespace.
|
|||
|
||||
GitLab Flavored Markdown recognizes the following:
|
||||
|
||||
| references | input | cross-project reference | shortcut inside same namespace |
|
||||
| :--------------------------------------------------- | :---------------------------- | :----------------------------------------- | :------------------------------- |
|
||||
| specific user | `@user_name` | | |
|
||||
| specific group | `@group_name` | | |
|
||||
| entire team | `@all` | | |
|
||||
| project | `namespace/project>` | | |
|
||||
| issue | ``#123`` | `namespace/project#123` | `project#123` |
|
||||
| merge request | `!123` | `namespace/project!123` | `project!123` |
|
||||
| snippet | `$123` | `namespace/project$123` | `project$123` |
|
||||
| [epic](group/epics/index.md) | `&123` | `group1/subgroup&123` | |
|
||||
| vulnerability **(ULTIMATE)** <sup>1</sup> | `[vulnerability:123]` | `[vulnerability:namespace/project/123]` | `[vulnerability:project/123]` |
|
||||
| feature flag | `[feature_flag:123]` | `[feature_flag:namespace/project/123]` | `[feature_flag:project/123]` |
|
||||
| label by ID | `~123` | `namespace/project~123` | `project~123` |
|
||||
| one-word label by name | `~bug` | `namespace/project~bug` | `project~bug` |
|
||||
| multi-word label by name | `~"feature request"` | `namespace/project~"feature request"` | `project~"feature request"` |
|
||||
| scoped label by name | `~"priority::high"` | `namespace/project~"priority::high"` | `project~"priority::high"` |
|
||||
| project milestone by ID | `%123` | `namespace/project%123` | `project%123` |
|
||||
| one-word milestone by name | `%v1.23` | `namespace/project%v1.23` | `project%v1.23` |
|
||||
| multi-word milestone by name | `%"release candidate"` | `namespace/project%"release candidate"` | `project%"release candidate"` |
|
||||
| specific commit | `9ba12248` | `namespace/project@9ba12248` | `project@9ba12248` |
|
||||
| commit range comparison | `9ba12248...b19a04f5` | `namespace/project@9ba12248...b19a04f5` | `project@9ba12248...b19a04f5` |
|
||||
| repository file references | `[README](doc/README.md)` | | |
|
||||
| repository file line references | `[README](doc/README.md#L13)` | | |
|
||||
| [alert](../operations/incident_management/alerts.md) | `^alert#123` | `namespace/project^alert#123` | `project^alert#123` |
|
||||
| contact | `[contact:test@example.com]` | | |
|
||||
| references | input | cross-project reference | shortcut inside same namespace |
|
||||
|:----------------------------------------------------------------------------|:------------------------------|:----------------------------------------|:-------------------------------|
|
||||
| specific user | `@user_name` | | |
|
||||
| specific group | `@group_name` | | |
|
||||
| entire team | `@all` | | |
|
||||
| project | `namespace/project>` | | |
|
||||
| issue | ``#123`` | `namespace/project#123` | `project#123` |
|
||||
| merge request | `!123` | `namespace/project!123` | `project!123` |
|
||||
| snippet | `$123` | `namespace/project$123` | `project$123` |
|
||||
| [epic](group/epics/index.md) | `&123` | `group1/subgroup&123` | |
|
||||
| [vulnerability](application_security/vulnerabilities/index.md) <sup>1</sup> | `[vulnerability:123]` | `[vulnerability:namespace/project/123]` | `[vulnerability:project/123]` |
|
||||
| feature flag | `[feature_flag:123]` | `[feature_flag:namespace/project/123]` | `[feature_flag:project/123]` |
|
||||
| label by ID | `~123` | `namespace/project~123` | `project~123` |
|
||||
| one-word label by name | `~bug` | `namespace/project~bug` | `project~bug` |
|
||||
| multi-word label by name | `~"feature request"` | `namespace/project~"feature request"` | `project~"feature request"` |
|
||||
| scoped label by name | `~"priority::high"` | `namespace/project~"priority::high"` | `project~"priority::high"` |
|
||||
| project milestone by ID | `%123` | `namespace/project%123` | `project%123` |
|
||||
| one-word milestone by name | `%v1.23` | `namespace/project%v1.23` | `project%v1.23` |
|
||||
| multi-word milestone by name | `%"release candidate"` | `namespace/project%"release candidate"` | `project%"release candidate"` |
|
||||
| specific commit | `9ba12248` | `namespace/project@9ba12248` | `project@9ba12248` |
|
||||
| commit range comparison | `9ba12248...b19a04f5` | `namespace/project@9ba12248...b19a04f5` | `project@9ba12248...b19a04f5` |
|
||||
| repository file references | `[README](doc/README.md)` | | |
|
||||
| repository file line references | `[README](doc/README.md#L13)` | | |
|
||||
| [alert](../operations/incident_management/alerts.md) | `^alert#123` | `namespace/project^alert#123` | `project^alert#123` |
|
||||
| contact | `[contact:test@example.com]` | | |
|
||||
|
||||
1. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222483) in GitLab 13.7.
|
||||
|
||||
|
@ -1486,7 +1486,7 @@ but they do not render properly on `docs.gitlab.com`:
|
|||
|
||||
#### Copy from spreadsheet and paste in Markdown
|
||||
|
||||
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27205) in GitLab 12.7.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27205) in GitLab 12.7.
|
||||
|
||||
If you're working in spreadsheet software (for example, Microsoft Excel, Google
|
||||
Sheets, or Apple Numbers), GitLab creates a Markdown table when you copy-and-paste
|
||||
|
|
|
@ -34,7 +34,8 @@ in the search field in the upper right corner:
|
|||
|
||||
> - Filtering by epics was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/195704) in GitLab 12.9.
|
||||
> - Filtering by child epics was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9029) in GitLab 13.0.
|
||||
> - Filtering by iterations was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6. Moved from GitLab Ultimate to Premium in 13.9.
|
||||
> - Filtering by iterations was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6.
|
||||
> - Filtering by iterations was moved from GitLab Ultimate to GitLab Premium in 13.9.
|
||||
> - Filtering by type was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322755) in GitLab 13.10 [with a flag](../../administration/feature_flags.md) named `vue_issues_list`. Disabled by default.
|
||||
|
||||
Follow these steps to filter the **Issues** and **Merge requests** list pages in projects and
|
||||
|
@ -127,14 +128,14 @@ the dropdown list) **Approved-By** and select the user.
|
|||
|
||||
![Filter MRs by approved by](img/filter_approved_by_merge_requests_v14_6.png)
|
||||
|
||||
### Filtering merge requests by reviewer **(FREE)**
|
||||
### Filtering merge requests by reviewer
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47605) in GitLab 13.7.
|
||||
|
||||
To filter review requested merge requests for a specific individual, you can type (or select from
|
||||
the dropdown list) **Reviewer** and select the user.
|
||||
|
||||
### Filtering merge requests by environment or deployment date **(FREE)**
|
||||
### Filtering merge requests by environment or deployment date
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44041) in GitLab 13.6.
|
||||
|
||||
|
@ -307,7 +308,7 @@ GitLab instance.
|
|||
## Search settings
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292941) in GitLab 13.8 [with a flag](../../administration/feature_flags.md) named `search_settings_in_page`. Disabled by default.
|
||||
> - [Added to Group, Administrator, and User settings](https://gitlab.com/groups/gitlab-org/-/epics/4842) in GitLab 13.9.
|
||||
> - [Added](https://gitlab.com/groups/gitlab-org/-/epics/4842) to Group, Administrator, and User settings in GitLab 13.9.
|
||||
> - [Feature flag `search_settings_in_page` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/294025) in GitLab 13.11.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/294025) in GitLab 13.11.
|
||||
|
||||
|
|
|
@ -37,8 +37,7 @@ You can create snippets in multiple ways, depending on whether you want to creat
|
|||
**New snippet**, or:
|
||||
- *If you're on a project's page,* select the plus icon (**{plus-square-o}**)
|
||||
in the top navigation bar, and then select **New snippet** from the
|
||||
**GitLab** (GitLab SaaS) or **Your Instance** (self-managed) section
|
||||
of the same dropdown list.
|
||||
**GitLab** section of the same dropdown list.
|
||||
- *For all other pages,* select the plus icon (**{plus-square-o}**)
|
||||
in the top navigation bar, then select **New snippet** from the dropdown list.
|
||||
- If you installed the [GitLab Workflow VS Code extension](project/repository/vscode.md),
|
||||
|
@ -153,8 +152,7 @@ To delete a file from your snippet through the GitLab UI:
|
|||
|
||||
1. Go to your snippet in the GitLab UI.
|
||||
1. Select **Edit** in the top right corner.
|
||||
1. Select **Delete file** alongside the filename of each file
|
||||
you wish to delete.
|
||||
1. Select **Delete file** alongside the filename of each file you wish to delete.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Clone snippets
|
||||
|
|
|
@ -1773,13 +1773,13 @@ msgstr ""
|
|||
msgid "AWS Access Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "AWS Access Key. Only required if not using role instance credentials"
|
||||
msgstr ""
|
||||
|
||||
msgid "AWS Secret Access Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "AWS Secret Access Key. Only required if not using role instance credentials"
|
||||
msgid "AWS access key ID (Optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "AWS secret access key (Optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "AWS service error: %{error}"
|
||||
|
@ -1839,9 +1839,6 @@ msgstr ""
|
|||
msgid "Access granted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Access key ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "Access requests"
|
||||
msgstr ""
|
||||
|
||||
|
@ -19864,9 +19861,6 @@ msgstr ""
|
|||
msgid "Integrations|Use default settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|When you mention a Jira issue in a commit or merge request, GitLab creates a remote link and comment (if enabled)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|You can now close this window and return to the GitLab for Jira application."
|
||||
msgstr ""
|
||||
|
||||
|
@ -20830,15 +20824,15 @@ msgstr ""
|
|||
msgid "JiraService|Define the type of Jira issue to create from a vulnerability."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Displaying Jira issues while leaving the GitLab issue functionality enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used."
|
||||
msgid "JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Enable Jira issue creation from vulnerabilities"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Enable Jira issues"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Enable Jira issues creation from vulnerabilities"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Enable Jira transitions"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20953,16 +20947,19 @@ msgstr ""
|
|||
msgid "JiraService|View Jira issues in GitLab"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Warning: All GitLab users that have access to this GitLab project are able to view all issues from the Jira project specified below."
|
||||
msgid "JiraService|Warning: All GitLab users with access to this GitLab project can view all issues from the Jira project you select."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Web URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of Jira issues and view any issue as read-only."
|
||||
msgid "JiraService|When a Jira issue is mentioned in a commit or merge request, a remote link and comment (if enabled) will be created."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|You must configure Jira before enabling this integration. For more details, read the %{jira_doc_link_start}Jira integration documentation%{link_end}."
|
||||
msgid "JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|You must configure Jira before enabling this integration. %{jira_doc_link_start}Learn more.%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Job"
|
||||
|
@ -25611,6 +25608,9 @@ msgstr ""
|
|||
msgid "Only reCAPTCHA v2 is supported:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only required if not using role instance credentials."
|
||||
msgstr ""
|
||||
|
||||
msgid "Only use lowercase letters, numbers, and underscores."
|
||||
msgstr ""
|
||||
|
||||
|
@ -32290,9 +32290,6 @@ msgstr ""
|
|||
msgid "Secret Detection"
|
||||
msgstr ""
|
||||
|
||||
msgid "Secret access key"
|
||||
msgstr ""
|
||||
|
||||
msgid "Secret token"
|
||||
msgstr ""
|
||||
|
||||
|
@ -32491,9 +32488,6 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|.yaml preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Action"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Actions"
|
||||
msgstr ""
|
||||
|
||||
|
@ -32536,9 +32530,6 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Executes a %{scanType} scan"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|If you are using Auto DevOps, your %{monospacedStart}auto-deploy-values.yaml%{monospacedEnd} file will not be updated if you change a policy in this section. Auto DevOps users should make changes by following the %{linkStart}Container Network Policy documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -32554,6 +32545,9 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|New policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|No actions defined - policy will not run."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|No description"
|
||||
msgstr ""
|
||||
|
||||
|
@ -32596,10 +32590,13 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|Require %{approvals} %{plural} from %{approvers} if any of the following occur:"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Rule"
|
||||
msgid "SecurityOrchestration|Rules"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Rules"
|
||||
msgid "SecurityOrchestration|Runs %{actions} and %{lastAction} scans"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Runs a %{action} scan"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Scan Execution"
|
||||
|
@ -34688,10 +34685,10 @@ msgstr ""
|
|||
msgid "SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance's code views and merge requests."
|
||||
msgstr ""
|
||||
|
||||
msgid "SourcegraphAdmin|If checked, only public projects will have code intelligence and communicate with Sourcegraph."
|
||||
msgid "SourcegraphAdmin|Learn more."
|
||||
msgstr ""
|
||||
|
||||
msgid "SourcegraphAdmin|More information"
|
||||
msgid "SourcegraphAdmin|Only public projects have code intelligence enabled and communicate with Sourcegraph."
|
||||
msgstr ""
|
||||
|
||||
msgid "SourcegraphAdmin|Save changes"
|
||||
|
@ -34700,7 +34697,7 @@ msgstr ""
|
|||
msgid "SourcegraphAdmin|Sourcegraph URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "SourcegraphAdmin|e.g. https://sourcegraph.example.com"
|
||||
msgid "SourcegraphAdmin|https://sourcegraph.example.com"
|
||||
msgstr ""
|
||||
|
||||
msgid "SourcegraphPreferences|This feature is experimental and currently limited to certain projects."
|
||||
|
|
38
scripts/ingest-reports-to-siem
Executable file
38
scripts/ingest-reports-to-siem
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3')
|
||||
const { fromIni } = require('@aws-sdk/credential-provider-ini')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const crypto = require('crypto')
|
||||
|
||||
function getMD5HashFromFile(data) {
|
||||
const hash = crypto.createHash('md5').update(data).digest('base64')
|
||||
return hash
|
||||
}
|
||||
|
||||
(async function () {
|
||||
const s3Client = new S3Client({
|
||||
region: 'us-east-2',
|
||||
credentials: fromIni({ profile: 'gl-logs-for-panther' }),
|
||||
})
|
||||
try {
|
||||
const file = 'gl-dependency-scanning-report.json'
|
||||
const data = fs.readFileSync(file)
|
||||
const responseData = await s3Client.send(
|
||||
new PutObjectCommand({
|
||||
Bucket: 'gl-logs-for-panther-test',
|
||||
Key: path.join('package_hunter_test', path.basename(file)),
|
||||
Body: data,
|
||||
ContentMD5: getMD5HashFromFile(data),
|
||||
}),
|
||||
)
|
||||
console.log('Successfully uploaded %s', file)
|
||||
} catch (err) {
|
||||
if (err.name === 'CredentialsProviderError' || err.name === 'AuthorizationHeaderMalformed')
|
||||
console.log('Could not upload the report. Are AWS credentials configured in ~/.aws/credentials?')
|
||||
else
|
||||
console.log('Unexpected error during upload.')
|
||||
process.exit(1)
|
||||
}
|
||||
})()
|
|
@ -28,63 +28,25 @@ RSpec.describe ApplicationExperiment, :experiment do
|
|||
end
|
||||
|
||||
describe "#publish" do
|
||||
let(:should_track) { true }
|
||||
|
||||
before do
|
||||
allow(application_experiment).to receive(:should_track?).and_return(should_track)
|
||||
end
|
||||
|
||||
it "tracks the assignment", :snowplow do
|
||||
expect(application_experiment).to receive(:track).with(:assignment)
|
||||
|
||||
application_experiment.publish
|
||||
end
|
||||
|
||||
it "adds to the published experiments" do
|
||||
# These are surfaced in the client layer by rendering them in the
|
||||
# _published_experiments.html.haml partial.
|
||||
application_experiment.publish
|
||||
|
||||
expect_snowplow_event(
|
||||
category: 'namespaced/stub',
|
||||
action: 'assignment',
|
||||
context: [{ schema: anything, data: anything }]
|
||||
expect(ApplicationExperiment.published_experiments['namespaced/stub']).to include(
|
||||
experiment: 'namespaced/stub',
|
||||
excluded: false,
|
||||
key: anything,
|
||||
variant: 'control'
|
||||
)
|
||||
end
|
||||
|
||||
it "publishes to the client" do
|
||||
expect(application_experiment).to receive(:publish_to_client)
|
||||
|
||||
application_experiment.publish
|
||||
end
|
||||
|
||||
context 'when we should not track' do
|
||||
let(:should_track) { false }
|
||||
|
||||
it 'does not track an event to Snowplow', :snowplow do
|
||||
application_experiment.publish
|
||||
|
||||
expect_no_snowplow_event
|
||||
end
|
||||
end
|
||||
|
||||
describe "#publish_to_client" do
|
||||
it "adds the data into Gon" do
|
||||
signature = { key: '86208ac54ca798e11f127e8b23ec396a', variant: 'control' }
|
||||
expect(Gon).to receive(:push).with({ experiment: { 'namespaced/stub' => hash_including(signature) } }, true)
|
||||
|
||||
application_experiment.publish_to_client
|
||||
end
|
||||
|
||||
it "handles when Gon raises exceptions (like when it can't be pushed into)" do
|
||||
expect(Gon).to receive(:push).and_raise(NoMethodError)
|
||||
|
||||
expect { application_experiment.publish_to_client }.not_to raise_error
|
||||
end
|
||||
|
||||
context 'when we should not track' do
|
||||
let(:should_track) { false }
|
||||
|
||||
it 'returns early' do
|
||||
expect(Gon).not_to receive(:push)
|
||||
|
||||
application_experiment.publish_to_client
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#publish_to_database' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
|
|
|
@ -40,10 +40,8 @@ RSpec.describe "User views incident" do
|
|||
visit(project_issues_incident_path(project, incident))
|
||||
end
|
||||
|
||||
it 'does not show the incident action', :js, :aggregate_failures do
|
||||
click_button 'Incident actions'
|
||||
|
||||
expect(page).not_to have_link('New incident')
|
||||
it 'does not show the incident actions', :js, :aggregate_failures do
|
||||
expect(page).not_to have_button('Incident actions')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -70,11 +70,6 @@ describe('RevokeButton', () => {
|
|||
expect(findRevokeButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('passes the buttonClass to the button', () => {
|
||||
wrapper = createComponent({ buttonClass: 'my-revoke-button' });
|
||||
expect(findRevokeButton().classes()).toContain('my-revoke-button');
|
||||
});
|
||||
|
||||
it('opens the modal', () => {
|
||||
findRevokeButton().trigger('click');
|
||||
expect(glModalDirective).toHaveBeenCalledWith(wrapper.vm.modalId);
|
||||
|
|
|
@ -33,19 +33,19 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_runners_query_name = 'get_runners.query.graphql'
|
||||
admin_runners_query = 'list/admin_runners.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_runners_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{admin_runners_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runners_query_name}.json" do
|
||||
it "#{fixtures_path}#{admin_runners_query}.json" do
|
||||
post_graphql(query, current_user: admin, variables: {})
|
||||
|
||||
expect_graphql_errors_to_be_empty
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runners_query_name}.paginated.json" do
|
||||
it "#{fixtures_path}#{admin_runners_query}.paginated.json" do
|
||||
post_graphql(query, current_user: admin, variables: { first: 2 })
|
||||
|
||||
expect_graphql_errors_to_be_empty
|
||||
|
@ -53,13 +53,13 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_runners_count_query_name = 'get_runners_count.query.graphql'
|
||||
admin_runners_count_query = 'list/admin_runners_count.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_runners_count_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{admin_runners_count_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runners_count_query_name}.json" do
|
||||
it "#{fixtures_path}#{admin_runners_count_query}.json" do
|
||||
post_graphql(query, current_user: admin, variables: {})
|
||||
|
||||
expect_graphql_errors_to_be_empty
|
||||
|
@ -67,13 +67,13 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_runner_query_name = 'get_runner.query.graphql'
|
||||
runner_query = 'details/runner.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_runner_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{runner_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runner_query_name}.json" do
|
||||
it "#{fixtures_path}#{runner_query}.json" do
|
||||
post_graphql(query, current_user: admin, variables: {
|
||||
id: instance_runner.to_global_id.to_s
|
||||
})
|
||||
|
@ -81,7 +81,7 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
expect_graphql_errors_to_be_empty
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runner_query_name}.with_group.json" do
|
||||
it "#{fixtures_path}#{runner_query}.with_group.json" do
|
||||
post_graphql(query, current_user: admin, variables: {
|
||||
id: group_runner.to_global_id.to_s
|
||||
})
|
||||
|
@ -91,13 +91,13 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_runner_projects_query_name = 'get_runner_projects.query.graphql'
|
||||
runner_projects_query = 'details/runner_projects.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_runner_projects_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{runner_projects_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runner_projects_query_name}.json" do
|
||||
it "#{fixtures_path}#{runner_projects_query}.json" do
|
||||
post_graphql(query, current_user: admin, variables: {
|
||||
id: project_runner.to_global_id.to_s
|
||||
})
|
||||
|
@ -107,13 +107,13 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_runner_jobs_query_name = 'get_runner_jobs.query.graphql'
|
||||
runner_jobs_query = 'details/runner_jobs.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_runner_jobs_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{runner_jobs_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_runner_jobs_query_name}.json" do
|
||||
it "#{fixtures_path}#{runner_jobs_query}.json" do
|
||||
post_graphql(query, current_user: admin, variables: {
|
||||
id: instance_runner.to_global_id.to_s
|
||||
})
|
||||
|
@ -131,13 +131,13 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_group_runners_query_name = 'get_group_runners.query.graphql'
|
||||
group_runners_query = 'list/group_runners.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_group_runners_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{group_runners_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_group_runners_query_name}.json" do
|
||||
it "#{fixtures_path}#{group_runners_query}.json" do
|
||||
post_graphql(query, current_user: group_owner, variables: {
|
||||
groupFullPath: group.full_path
|
||||
})
|
||||
|
@ -145,7 +145,7 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
expect_graphql_errors_to_be_empty
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_group_runners_query_name}.paginated.json" do
|
||||
it "#{fixtures_path}#{group_runners_query}.paginated.json" do
|
||||
post_graphql(query, current_user: group_owner, variables: {
|
||||
groupFullPath: group.full_path,
|
||||
first: 1
|
||||
|
@ -156,13 +156,13 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
describe GraphQL::Query, type: :request do
|
||||
get_group_runners_count_query_name = 'get_group_runners_count.query.graphql'
|
||||
group_runners_count_query = 'list/group_runners_count.query.graphql'
|
||||
|
||||
let_it_be(:query) do
|
||||
get_graphql_query_as_string("#{query_path}#{get_group_runners_count_query_name}")
|
||||
get_graphql_query_as_string("#{query_path}#{group_runners_count_query}")
|
||||
end
|
||||
|
||||
it "#{fixtures_path}#{get_group_runners_count_query_name}.json" do
|
||||
it "#{fixtures_path}#{group_runners_count_query}.json" do
|
||||
post_graphql(query, current_user: group_owner, variables: {
|
||||
groupFullPath: group.full_path
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { GlButton, GlDropdown, GlDropdownItem, GlLink, GlModal } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import { GlButton, GlDropdownItem, GlLink, GlModal } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { mockTracking } from 'helpers/tracking_helper';
|
||||
|
@ -65,12 +65,17 @@ describe('HeaderActions component', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const findToggleIssueStateButton = () => wrapper.findComponent(GlButton);
|
||||
const findDropdownAt = (index) => wrapper.findAllComponents(GlDropdown).at(index);
|
||||
const findMobileDropdownItems = () => findDropdownAt(0).findAllComponents(GlDropdownItem);
|
||||
const findDesktopDropdownItems = () => findDropdownAt(1).findAllComponents(GlDropdownItem);
|
||||
const findModal = () => wrapper.findComponent(GlModal);
|
||||
const findModalLinkAt = (index) => findModal().findAllComponents(GlLink).at(index);
|
||||
const findToggleIssueStateButton = () => wrapper.find(GlButton);
|
||||
|
||||
const findDropdownBy = (dataTestId) => wrapper.find(`[data-testid="${dataTestId}"]`);
|
||||
const findMobileDropdown = () => findDropdownBy('mobile-dropdown');
|
||||
const findDesktopDropdown = () => findDropdownBy('desktop-dropdown');
|
||||
const findMobileDropdownItems = () => findMobileDropdown().findAll(GlDropdownItem);
|
||||
const findDesktopDropdownItems = () => findDesktopDropdown().findAll(GlDropdownItem);
|
||||
|
||||
const findModal = () => wrapper.find(GlModal);
|
||||
|
||||
const findModalLinkAt = (index) => findModal().findAll(GlLink).at(index);
|
||||
|
||||
const mountComponent = ({
|
||||
props = {},
|
||||
|
@ -161,10 +166,10 @@ describe('HeaderActions component', () => {
|
|||
});
|
||||
|
||||
describe.each`
|
||||
description | isCloseIssueItemVisible | findDropdownItems
|
||||
${'mobile dropdown'} | ${true} | ${findMobileDropdownItems}
|
||||
${'desktop dropdown'} | ${false} | ${findDesktopDropdownItems}
|
||||
`('$description', ({ isCloseIssueItemVisible, findDropdownItems }) => {
|
||||
description | isCloseIssueItemVisible | findDropdownItems | findDropdown
|
||||
${'mobile dropdown'} | ${true} | ${findMobileDropdownItems} | ${findMobileDropdown}
|
||||
${'desktop dropdown'} | ${false} | ${findDesktopDropdownItems} | ${findDesktopDropdown}
|
||||
`('$description', ({ isCloseIssueItemVisible, findDropdownItems, findDropdown }) => {
|
||||
describe.each`
|
||||
description | itemText | isItemVisible | canUpdateIssue | canCreateIssue | isIssueAuthor | canReportSpam | canPromoteToEpic | canDestroyIssue
|
||||
${`when user can update ${issueType}`} | ${`Close ${issueType}`} | ${isCloseIssueItemVisible} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
|
@ -214,6 +219,24 @@ describe('HeaderActions component', () => {
|
|||
});
|
||||
},
|
||||
);
|
||||
|
||||
describe(`when user can update but not create ${issueType}`, () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mountComponent({
|
||||
props: {
|
||||
canUpdateIssue: true,
|
||||
canCreateIssue: false,
|
||||
isIssueAuthor: true,
|
||||
issueType,
|
||||
canReportSpam: false,
|
||||
canPromoteToEpic: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
it(`${isCloseIssueItemVisible ? 'shows' : 'hides'} the dropdown button`, () => {
|
||||
expect(findDropdown().exists()).toBe(isCloseIssueItemVisible);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { shallowMountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import InlineConflictLines from '~/merge_conflicts/components/inline_conflict_lines.vue';
|
||||
import ParallelConflictLines from '~/merge_conflicts/components/parallel_conflict_lines.vue';
|
||||
import component from '~/merge_conflicts/merge_conflict_resolver_app.vue';
|
||||
|
@ -18,7 +18,7 @@ describe('Merge Conflict Resolver App', () => {
|
|||
const decoratedMockFiles = decorateFiles(conflictsMock.files);
|
||||
|
||||
const mountComponent = () => {
|
||||
wrapper = shallowMount(component, {
|
||||
wrapper = shallowMountExtended(component, {
|
||||
store,
|
||||
stubs: { GlSprintf },
|
||||
provide() {
|
||||
|
@ -41,15 +41,17 @@ describe('Merge Conflict Resolver App', () => {
|
|||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findConflictsCount = () => wrapper.find('[data-testid="conflicts-count"]');
|
||||
const findFiles = () => wrapper.findAll('[data-testid="files"]');
|
||||
const findFileHeader = (w = wrapper) => w.find('[data-testid="file-name"]');
|
||||
const findFileInteractiveButton = (w = wrapper) => w.find('[data-testid="interactive-button"]');
|
||||
const findFileInlineButton = (w = wrapper) => w.find('[data-testid="inline-button"]');
|
||||
const findSideBySideButton = () => wrapper.find('[data-testid="side-by-side"]');
|
||||
const findLoadingSpinner = () => wrapper.findByTestId('loading-spinner');
|
||||
const findConflictsCount = () => wrapper.findByTestId('conflicts-count');
|
||||
const findFiles = () => wrapper.findAllByTestId('files');
|
||||
const findFileHeader = (w = wrapper) => extendedWrapper(w).findByTestId('file-name');
|
||||
const findFileInteractiveButton = (w = wrapper) =>
|
||||
extendedWrapper(w).findByTestId('interactive-button');
|
||||
const findFileInlineButton = (w = wrapper) => extendedWrapper(w).findByTestId('inline-button');
|
||||
const findSideBySideButton = () => wrapper.findByTestId('side-by-side');
|
||||
const findInlineConflictLines = (w = wrapper) => w.find(InlineConflictLines);
|
||||
const findParallelConflictLines = (w = wrapper) => w.find(ParallelConflictLines);
|
||||
const findCommitMessageTextarea = () => wrapper.find('[data-testid="commit-message"]');
|
||||
const findCommitMessageTextarea = () => wrapper.findByTestId('commit-message');
|
||||
|
||||
it('shows the amount of conflicts', () => {
|
||||
mountComponent();
|
||||
|
@ -60,6 +62,19 @@ describe('Merge Conflict Resolver App', () => {
|
|||
expect(title.text().trim()).toBe('Showing 3 conflicts between test-conflicts and main');
|
||||
});
|
||||
|
||||
it('shows a loading spinner while loading', () => {
|
||||
store.commit('SET_LOADING_STATE', true);
|
||||
mountComponent();
|
||||
|
||||
expect(findLoadingSpinner().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show a loading spinner once loaded', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findLoadingSpinner().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('files', () => {
|
||||
it('shows one file area for each file', () => {
|
||||
mountComponent();
|
||||
|
|
|
@ -18,12 +18,15 @@ import {
|
|||
COMMIT_SUCCESS,
|
||||
COMMIT_SUCCESS_WITH_REDIRECT,
|
||||
COMMIT_FAILURE,
|
||||
EDITOR_APP_STATUS_LOADING,
|
||||
} from '~/pipeline_editor/constants';
|
||||
import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
|
||||
import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.query.graphql';
|
||||
import getTemplate from '~/pipeline_editor/graphql/queries/get_starter_template.query.graphql';
|
||||
import getLatestCommitShaQuery from '~/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql';
|
||||
import getPipelineQuery from '~/pipeline_editor/graphql/queries/pipeline.query.graphql';
|
||||
import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.query.graphql';
|
||||
import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
|
||||
|
||||
import PipelineEditorApp from '~/pipeline_editor/pipeline_editor_app.vue';
|
||||
import PipelineEditorHome from '~/pipeline_editor/pipeline_editor_home.vue';
|
||||
|
@ -84,9 +87,6 @@ describe('Pipeline editor app component', () => {
|
|||
initialCiFileContent: {
|
||||
loading: blobLoading,
|
||||
},
|
||||
ciConfigData: {
|
||||
loading: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -94,7 +94,11 @@ describe('Pipeline editor app component', () => {
|
|||
});
|
||||
};
|
||||
|
||||
const createComponentWithApollo = async ({ provide = {}, stubs = {} } = {}) => {
|
||||
const createComponentWithApollo = async ({
|
||||
provide = {},
|
||||
stubs = {},
|
||||
withUndefinedBranch = false,
|
||||
} = {}) => {
|
||||
const handlers = [
|
||||
[getBlobContent, mockBlobContentData],
|
||||
[getCiConfigData, mockCiConfigData],
|
||||
|
@ -105,6 +109,31 @@ describe('Pipeline editor app component', () => {
|
|||
|
||||
mockApollo = createMockApollo(handlers, resolvers);
|
||||
|
||||
if (!withUndefinedBranch) {
|
||||
mockApollo.clients.defaultClient.cache.writeQuery({
|
||||
query: getCurrentBranch,
|
||||
data: {
|
||||
workBranches: {
|
||||
__typename: 'BranchList',
|
||||
current: {
|
||||
__typename: 'WorkBranch',
|
||||
name: mockDefaultBranch,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
mockApollo.clients.defaultClient.cache.writeQuery({
|
||||
query: getAppStatus,
|
||||
data: {
|
||||
app: {
|
||||
__typename: 'AppData',
|
||||
status: EDITOR_APP_STATUS_LOADING,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const options = {
|
||||
localVue,
|
||||
mocks: {},
|
||||
|
@ -145,6 +174,55 @@ describe('Pipeline editor app component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('skipping queries', () => {
|
||||
describe('when branchName is undefined', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponentWithApollo({ withUndefinedBranch: true });
|
||||
});
|
||||
|
||||
it('does not calls getBlobContent', () => {
|
||||
expect(mockBlobContentData).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when branchName is defined', () => {
|
||||
beforeEach(async () => {
|
||||
await createComponentWithApollo();
|
||||
});
|
||||
|
||||
it('calls getBlobContent', () => {
|
||||
expect(mockBlobContentData).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when commit sha is undefined', () => {
|
||||
beforeEach(async () => {
|
||||
mockLatestCommitShaQuery.mockResolvedValue(undefined);
|
||||
await createComponentWithApollo();
|
||||
});
|
||||
|
||||
it('calls getBlobContent', () => {
|
||||
expect(mockBlobContentData).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not call ciConfigData', () => {
|
||||
expect(mockCiConfigData).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when commit sha is defined', () => {
|
||||
beforeEach(async () => {
|
||||
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
|
||||
mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
|
||||
await createComponentWithApollo();
|
||||
});
|
||||
|
||||
it('calls ciConfigData', () => {
|
||||
expect(mockCiConfigData).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when queries are called', () => {
|
||||
beforeEach(() => {
|
||||
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
|
||||
|
|
|
@ -7,7 +7,7 @@ import { createAlert } from '~/flash';
|
|||
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import RunnerHeader from '~/runner/components/runner_header.vue';
|
||||
import getRunnerQuery from '~/runner/graphql/get_runner.query.graphql';
|
||||
import runnerQuery from '~/runner/graphql/details/runner.query.graphql';
|
||||
import AdminRunnerEditApp from '~//runner/admin_runner_edit/admin_runner_edit_app.vue';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
|
||||
|
@ -29,7 +29,7 @@ describe('AdminRunnerEditApp', () => {
|
|||
|
||||
const createComponentWithApollo = ({ props = {}, mountFn = shallowMount } = {}) => {
|
||||
wrapper = mountFn(AdminRunnerEditApp, {
|
||||
apolloProvider: createMockApollo([[getRunnerQuery, mockRunnerQuery]]),
|
||||
apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
|
||||
propsData: {
|
||||
runnerId: mockRunnerId,
|
||||
...props,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
|||
import RunnerHeader from '~/runner/components/runner_header.vue';
|
||||
import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
|
||||
import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
|
||||
import getRunnerQuery from '~/runner/graphql/get_runner.query.graphql';
|
||||
import runnerQuery from '~/runner/graphql/details/runner.query.graphql';
|
||||
import AdminRunnerShowApp from '~/runner/admin_runner_show/admin_runner_show_app.vue';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
|
||||
|
@ -42,7 +42,7 @@ describe('AdminRunnerShowApp', () => {
|
|||
|
||||
const createComponent = ({ props = {}, mountFn = shallowMount } = {}) => {
|
||||
wrapper = mountFn(AdminRunnerShowApp, {
|
||||
apolloProvider: createMockApollo([[getRunnerQuery, mockRunnerQuery]]),
|
||||
apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
|
||||
propsData: {
|
||||
runnerId: mockRunnerId,
|
||||
...props,
|
||||
|
|
|
@ -35,8 +35,8 @@ import {
|
|||
STATUS_ACTIVE,
|
||||
RUNNER_PAGE_SIZE,
|
||||
} from '~/runner/constants';
|
||||
import getRunnersQuery from '~/runner/graphql/get_runners.query.graphql';
|
||||
import getRunnersCountQuery from '~/runner/graphql/get_runners_count.query.graphql';
|
||||
import adminRunnersQuery from '~/runner/graphql/list/admin_runners.query.graphql';
|
||||
import adminRunnersCountQuery from '~/runner/graphql/list/admin_runners_count.query.graphql';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
|
||||
|
@ -71,8 +71,8 @@ describe('AdminRunnersApp', () => {
|
|||
|
||||
const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
|
||||
const handlers = [
|
||||
[getRunnersQuery, mockRunnersQuery],
|
||||
[getRunnersCountQuery, mockRunnersCountQuery],
|
||||
[adminRunnersQuery, mockRunnersQuery],
|
||||
[adminRunnersCountQuery, mockRunnersCountQuery],
|
||||
];
|
||||
|
||||
wrapper = mountFn(AdminRunnersApp, {
|
||||
|
|
|
@ -8,7 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { createAlert } from '~/flash';
|
||||
import RegistrationTokenResetDropdownItem from '~/runner/components/registration/registration_token_reset_dropdown_item.vue';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
import runnersRegistrationTokenResetMutation from '~/runner/graphql/runners_registration_token_reset.mutation.graphql';
|
||||
import runnersRegistrationTokenResetMutation from '~/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
|
|||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql';
|
||||
import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
|
|
|
@ -11,7 +11,7 @@ import RunnerPagination from '~/runner/components/runner_pagination.vue';
|
|||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '~/runner/constants';
|
||||
|
||||
import getRunnerJobsQuery from '~/runner/graphql/get_runner_jobs.query.graphql';
|
||||
import runnerJobsQuery from '~/runner/graphql/details/runner_jobs.query.graphql';
|
||||
|
||||
import { runnerData, runnerJobsData } from '../mock_data';
|
||||
|
||||
|
@ -34,7 +34,7 @@ describe('RunnerJobs', () => {
|
|||
|
||||
const createComponent = ({ mountFn = shallowMountExtended } = {}) => {
|
||||
wrapper = mountFn(RunnerJobs, {
|
||||
apolloProvider: createMockApollo([[getRunnerJobsQuery, mockRunnerJobsQuery]]),
|
||||
apolloProvider: createMockApollo([[runnerJobsQuery, mockRunnerJobsQuery]]),
|
||||
propsData: {
|
||||
runner: mockRunner,
|
||||
},
|
||||
|
|
|
@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
|
|||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import runnerToggleActiveMutation from '~/runner/graphql/runner_toggle_active.mutation.graphql';
|
||||
import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { createAlert } from '~/flash';
|
||||
|
|
|
@ -16,7 +16,7 @@ import RunnerAssignedItem from '~/runner/components/runner_assigned_item.vue';
|
|||
import RunnerPagination from '~/runner/components/runner_pagination.vue';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
|
||||
import getRunnerProjectsQuery from '~/runner/graphql/get_runner_projects.query.graphql';
|
||||
import runnerProjectsQuery from '~/runner/graphql/details/runner_projects.query.graphql';
|
||||
|
||||
import { runnerData, runnerProjectsData } from '../mock_data';
|
||||
|
||||
|
@ -40,7 +40,7 @@ describe('RunnerProjects', () => {
|
|||
|
||||
const createComponent = ({ mountFn = shallowMountExtended } = {}) => {
|
||||
wrapper = mountFn(RunnerProjects, {
|
||||
apolloProvider: createMockApollo([[getRunnerProjectsQuery, mockRunnerProjectsQuery]]),
|
||||
apolloProvider: createMockApollo([[runnerProjectsQuery, mockRunnerProjectsQuery]]),
|
||||
propsData: {
|
||||
runner: mockRunner,
|
||||
},
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
ACCESS_LEVEL_REF_PROTECTED,
|
||||
ACCESS_LEVEL_NOT_PROTECTED,
|
||||
} from '~/runner/constants';
|
||||
import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql';
|
||||
import runnerUpdateMutation from '~/runner/graphql/details/runner_update.mutation.graphql';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { runnerData } from '../mock_data';
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ import {
|
|||
RUNNER_PAGE_SIZE,
|
||||
I18N_EDIT,
|
||||
} from '~/runner/constants';
|
||||
import getGroupRunnersQuery from '~/runner/graphql/get_group_runners.query.graphql';
|
||||
import getGroupRunnersCountQuery from '~/runner/graphql/get_group_runners_count.query.graphql';
|
||||
import getGroupRunnersQuery from '~/runner/graphql/list/group_runners.query.graphql';
|
||||
import getGroupRunnersCountQuery from '~/runner/graphql/list/group_runners_count.query.graphql';
|
||||
import GroupRunnersApp from '~/runner/group_runners/group_runners_app.vue';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
// Fixtures generated by: spec/frontend/fixtures/runner.rb
|
||||
|
||||
// Admin queries
|
||||
import runnersData from 'test_fixtures/graphql/runner/get_runners.query.graphql.json';
|
||||
import runnersCountData from 'test_fixtures/graphql/runner/get_runners_count.query.graphql.json';
|
||||
import runnersDataPaginated from 'test_fixtures/graphql/runner/get_runners.query.graphql.paginated.json';
|
||||
import runnerData from 'test_fixtures/graphql/runner/get_runner.query.graphql.json';
|
||||
import runnerWithGroupData from 'test_fixtures/graphql/runner/get_runner.query.graphql.with_group.json';
|
||||
import runnerProjectsData from 'test_fixtures/graphql/runner/get_runner_projects.query.graphql.json';
|
||||
import runnerJobsData from 'test_fixtures/graphql/runner/get_runner_jobs.query.graphql.json';
|
||||
// List queries
|
||||
import runnersData from 'test_fixtures/graphql/runner/list/admin_runners.query.graphql.json';
|
||||
import runnersDataPaginated from 'test_fixtures/graphql/runner/list/admin_runners.query.graphql.paginated.json';
|
||||
import runnersCountData from 'test_fixtures/graphql/runner/list/admin_runners_count.query.graphql.json';
|
||||
import groupRunnersData from 'test_fixtures/graphql/runner/list/group_runners.query.graphql.json';
|
||||
import groupRunnersDataPaginated from 'test_fixtures/graphql/runner/list/group_runners.query.graphql.paginated.json';
|
||||
import groupRunnersCountData from 'test_fixtures/graphql/runner/list/group_runners_count.query.graphql.json';
|
||||
|
||||
// Group queries
|
||||
import groupRunnersData from 'test_fixtures/graphql/runner/get_group_runners.query.graphql.json';
|
||||
import groupRunnersCountData from 'test_fixtures/graphql/runner/get_group_runners_count.query.graphql.json';
|
||||
import groupRunnersDataPaginated from 'test_fixtures/graphql/runner/get_group_runners.query.graphql.paginated.json';
|
||||
// Details queries
|
||||
import runnerData from 'test_fixtures/graphql/runner/details/runner.query.graphql.json';
|
||||
import runnerWithGroupData from 'test_fixtures/graphql/runner/details/runner.query.graphql.with_group.json';
|
||||
import runnerProjectsData from 'test_fixtures/graphql/runner/details/runner_projects.query.graphql.json';
|
||||
import runnerJobsData from 'test_fixtures/graphql/runner/details/runner_jobs.query.graphql.json';
|
||||
|
||||
export {
|
||||
runnersData,
|
||||
|
|
20
spec/helpers/deploy_tokens_helper_spec.rb
Normal file
20
spec/helpers/deploy_tokens_helper_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe DeployTokensHelper do
|
||||
describe '#deploy_token_revoke_button_data' do
|
||||
let_it_be(:token) { build(:deploy_token) }
|
||||
let_it_be(:project) { build(:project) }
|
||||
let_it_be(:revoke_deploy_token_path) { '/foobar/baz/-/deploy_tokens/1/revoke' }
|
||||
|
||||
it 'returns expected hash' do
|
||||
expect(helper).to receive(:revoke_deploy_token_path).with(project, token).and_return(revoke_deploy_token_path)
|
||||
|
||||
expect(helper.deploy_token_revoke_button_data(token: token, group_or_project: project)).to match({
|
||||
token: token.to_json(only: [:id, :name]),
|
||||
revoke_path: revoke_deploy_token_path
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
|
@ -49,7 +49,7 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProject
|
|||
|
||||
it 'invalidates the markdown cache of related projects' do
|
||||
expect(subject).to receive(:remove_cached_html_for_projects)
|
||||
.with(projects.map(&:id))
|
||||
.with(a_collection_containing_exactly(*projects.map(&:id)))
|
||||
|
||||
subject.rename_projects
|
||||
end
|
||||
|
|
|
@ -390,26 +390,8 @@ RSpec.describe Group do
|
|||
let!(:old_parent) { create(:group, parent: root) }
|
||||
let!(:new_parent) { create(:group, parent: root) }
|
||||
|
||||
context 'with FOR UPDATE lock' do
|
||||
before do
|
||||
stub_feature_flags(for_no_key_update_lock: false)
|
||||
subject
|
||||
reload_models(old_parent, new_parent, group)
|
||||
end
|
||||
|
||||
it 'updates traversal_ids' do
|
||||
expect(group.traversal_ids).to eq [root.id, new_parent.id, group.id]
|
||||
end
|
||||
|
||||
it_behaves_like 'hierarchy with traversal_ids'
|
||||
it_behaves_like 'locked row', 'FOR UPDATE' do
|
||||
let(:row) { root }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with FOR NO KEY UPDATE lock' do
|
||||
before do
|
||||
stub_feature_flags(for_no_key_update_lock: true)
|
||||
subject
|
||||
reload_models(old_parent, new_parent, group)
|
||||
end
|
||||
|
@ -419,7 +401,7 @@ RSpec.describe Group do
|
|||
end
|
||||
|
||||
it_behaves_like 'hierarchy with traversal_ids'
|
||||
it_behaves_like 'locked row', 'FOR NO KEY UPDATE' do
|
||||
it_behaves_like 'locked row' do
|
||||
let(:row) { root }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,24 +68,11 @@ RSpec.describe Namespace::TraversalHierarchy, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'locked row', 'FOR UPDATE' do
|
||||
it_behaves_like 'locked row' do
|
||||
let(:recorded_queries) { ActiveRecord::QueryRecorder.new }
|
||||
let(:row) { root }
|
||||
|
||||
before do
|
||||
stub_feature_flags(for_no_key_update_lock: false)
|
||||
|
||||
recorded_queries.record { subject }
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'locked row', 'FOR NO KEY UPDATE' do
|
||||
let(:recorded_queries) { ActiveRecord::QueryRecorder.new }
|
||||
let(:row) { root }
|
||||
|
||||
before do
|
||||
stub_feature_flags(for_no_key_update_lock: true)
|
||||
|
||||
recorded_queries.record { subject }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -436,17 +436,7 @@ RSpec.describe Namespace do
|
|||
it { expect(namespace.traversal_ids).to eq [namespace.id] }
|
||||
end
|
||||
|
||||
context 'with before_commit callback' do
|
||||
it_behaves_like 'default traversal_ids'
|
||||
end
|
||||
|
||||
context 'with after_create callback' do
|
||||
before do
|
||||
stub_feature_flags(sync_traversal_ids_before_commit: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'default traversal_ids'
|
||||
end
|
||||
it_behaves_like 'default traversal_ids'
|
||||
end
|
||||
|
||||
describe "after_commit :expire_child_caches" do
|
||||
|
|
|
@ -262,17 +262,7 @@ RSpec.describe Project, factory_default: :keep do
|
|||
end
|
||||
end
|
||||
|
||||
context 'sync-ing traversal_ids in before_commit callback' do
|
||||
it_behaves_like 'creates project namespace'
|
||||
end
|
||||
|
||||
context 'sync-ing traversal_ids in after_create callback' do
|
||||
before do
|
||||
stub_feature_flags(sync_traversal_ids_before_commit: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'creates project namespace'
|
||||
end
|
||||
it_behaves_like 'creates project namespace'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -85,14 +85,6 @@ RSpec.describe Groups::CreateService, '#execute' do
|
|||
context 'with before_commit callback' do
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
|
||||
context 'with after_create callback' do
|
||||
before do
|
||||
stub_feature_flags(sync_traversal_ids_before_commit: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user can not create a group' do
|
||||
|
@ -119,17 +111,7 @@ RSpec.describe Groups::CreateService, '#execute' do
|
|||
expect { subject }.not_to change(OnboardingProgress, :count).from(0)
|
||||
end
|
||||
|
||||
context 'with before_commit callback' do
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
|
||||
context 'with after_create callback' do
|
||||
before do
|
||||
stub_feature_flags(sync_traversal_ids_before_commit: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
|
||||
context 'as guest' do
|
||||
|
|
|
@ -225,17 +225,7 @@ RSpec.describe Projects::CreateService, '#execute' do
|
|||
expect(project.project_namespace).to be_in_sync_with_project(project)
|
||||
end
|
||||
|
||||
context 'with before_commit callback' do
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
|
||||
context 'with after_create callback' do
|
||||
before do
|
||||
stub_feature_flags(sync_traversal_ids_before_commit: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
it_behaves_like 'has sync-ed traversal_ids'
|
||||
end
|
||||
|
||||
context 'group sharing', :sidekiq_inline do
|
||||
|
|
|
@ -49,6 +49,7 @@ module SimpleCovEnv
|
|||
|
||||
def configure_profile
|
||||
SimpleCov.configure do
|
||||
enable_coverage :branch
|
||||
load_profile 'test_frameworks'
|
||||
track_files '{app,config/initializers,config/initializers_before_autoloader,db/post_migrate,haml_lint,lib,rubocop,tooling}/**/*.rb'
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
# Ensure a transaction also occurred.
|
||||
# Be careful! This form of spec is not foolproof, but better than nothing.
|
||||
|
||||
RSpec.shared_examples 'locked row' do |lock_type|
|
||||
RSpec.shared_examples 'locked row' do
|
||||
it "has locked row" do
|
||||
table_name = row.class.table_name
|
||||
ids_regex = /SELECT.*FROM.*#{table_name}.*"#{table_name}"."id" = #{row.id}.+#{lock_type}/m
|
||||
ids_regex = /SELECT.*FROM.*#{table_name}.*"#{table_name}"."id" = #{row.id}.+FOR NO KEY UPDATE/m
|
||||
|
||||
expect(recorded_queries.log).to include a_string_matching 'SAVEPOINT'
|
||||
expect(recorded_queries.log).to include a_string_matching ids_regex
|
||||
|
|
|
@ -16,8 +16,8 @@ RSpec.describe 'admin/application_settings/_eks' do
|
|||
shared_examples 'EKS secret access key input' do
|
||||
it 'renders an empty password field' do
|
||||
render
|
||||
expect(rendered).to have_field('Secret access key', type: 'password')
|
||||
expect(page.find_field('Secret access key').value).to be_blank
|
||||
expect(rendered).to have_field('AWS secret access key (Optional)', type: 'password')
|
||||
expect(page.find_field('AWS secret access key (Optional)').value).to be_blank
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,22 +4,20 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'layouts/_published_experiments', :experiment do
|
||||
before do
|
||||
stub_const('TestControlExperiment', ApplicationExperiment)
|
||||
stub_const('TestCandidateExperiment', ApplicationExperiment)
|
||||
stub_const('TestExcludedExperiment', ApplicationExperiment)
|
||||
# Stub each experiment to be enabled, otherwise tracking does not happen.
|
||||
stub_experiments(
|
||||
test_control: :control,
|
||||
test_excluded: true,
|
||||
test_published_only: :control,
|
||||
test_candidate: :candidate,
|
||||
test_variant: :variant_name
|
||||
)
|
||||
|
||||
TestControlExperiment.new('test_control').tap do |e|
|
||||
e.variant(:control)
|
||||
e.publish
|
||||
end
|
||||
TestCandidateExperiment.new('test_candidate').tap do |e|
|
||||
e.variant(:candidate)
|
||||
e.publish
|
||||
end
|
||||
TestExcludedExperiment.new('test_excluded').tap do |e|
|
||||
e.exclude!
|
||||
e.publish
|
||||
end
|
||||
experiment(:test_control) { }
|
||||
experiment(:test_excluded) { |e| e.exclude! }
|
||||
experiment(:test_candidate) { |e| e.candidate { } }
|
||||
experiment(:test_variant) { |e| e.variant(:variant_name) { } }
|
||||
experiment(:test_published_only).publish
|
||||
|
||||
render
|
||||
end
|
||||
|
@ -29,7 +27,9 @@ RSpec.describe 'layouts/_published_experiments', :experiment do
|
|||
|
||||
expect(output).to include('gl.experiments = {')
|
||||
expect(output).to match(/"test_control":\{[^}]*"variant":"control"/)
|
||||
expect(output).to match(/"test_candidate":\{[^}]*"variant":"candidate"/)
|
||||
expect(output).not_to include('"test_excluded"')
|
||||
expect(output).to match(/"test_candidate":\{[^}]*"variant":"candidate"/)
|
||||
expect(output).to match(/"test_variant":\{[^}]*"variant":"variant_name"/)
|
||||
expect(output).to match(/"test_published_only":\{[^}]*"variant":"control"/)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue