Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5147cd60f1
commit
01034c2c45
63 changed files with 1019 additions and 374 deletions
|
@ -37,6 +37,7 @@ AllCops:
|
|||
- 'file_hooks/**/*'
|
||||
- 'workhorse/**/*'
|
||||
- 'spec/support/*.git/**/*' # e.g. spec/support/gitlab-git-test.git
|
||||
- 'db/ci_migrate/*.rb' # since the `db/ci_migrate` is a symlinked to `db/migrate`
|
||||
CacheRootDirectory: tmp
|
||||
MaxFilesInCache: 25000
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
6430f0f4df82aecc0b282d8fb620d1d9219a6aee
|
||||
59dfc252c79b7f9d290a3ede54c9ba8a3b12d4bd
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -339,7 +339,7 @@ gem 'warning', '~> 1.2.0'
|
|||
|
||||
group :development do
|
||||
gem 'lefthook', '~> 0.7.0', require: false
|
||||
gem 'solargraph', '~> 0.42', require: false
|
||||
gem 'solargraph', '~> 0.43', require: false
|
||||
|
||||
gem 'letter_opener_web', '~> 1.4.0'
|
||||
|
||||
|
|
|
@ -1206,7 +1206,7 @@ GEM
|
|||
slack-messenger (2.3.4)
|
||||
snowplow-tracker (0.6.1)
|
||||
contracts (~> 0.7, <= 0.11)
|
||||
solargraph (0.42.3)
|
||||
solargraph (0.43.0)
|
||||
backport (~> 1.2)
|
||||
benchmark
|
||||
bundler (>= 1.17.2)
|
||||
|
@ -1631,7 +1631,7 @@ DEPENDENCIES
|
|||
simplecov-cobertura (~> 1.3.1)
|
||||
slack-messenger (~> 2.3.4)
|
||||
snowplow-tracker (~> 0.6.1)
|
||||
solargraph (~> 0.42)
|
||||
solargraph (~> 0.43)
|
||||
spamcheck (~> 0.1.0)
|
||||
spring (~> 2.1.0)
|
||||
spring-commands-rspec (~> 1.0.4)
|
||||
|
|
|
@ -9,8 +9,7 @@ import { toNumber, omit } from 'lodash';
|
|||
import createFlash from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { scrollToElement, historyPushState } from '~/lib/utils/common_utils';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { setUrlParams, urlParamsToObject, getParameterByName } from '~/lib/utils/url_utility';
|
||||
import { setUrlParams, queryToObject, getParameterByName } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import initManualOrdering from '~/manual_ordering';
|
||||
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
|
@ -264,8 +263,7 @@ export default {
|
|||
});
|
||||
},
|
||||
getQueryObject() {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
return urlParamsToObject(window.location.search);
|
||||
return queryToObject(window.location.search, { gatherArrays: true });
|
||||
},
|
||||
onPaginate(newPage) {
|
||||
if (newPage === this.page) return;
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
scrollUp,
|
||||
} from '~/lib/utils/scroll_utils';
|
||||
import { __ } from '~/locale';
|
||||
import { reportToSentry } from '../utils';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
export const init = ({ dispatch }, { endpoint, logState, pagePath }) => {
|
||||
|
@ -175,11 +176,14 @@ export const fetchTrace = ({ dispatch, state }) =>
|
|||
dispatch('startPollingTrace');
|
||||
}
|
||||
})
|
||||
.catch((e) =>
|
||||
e.response.status === httpStatusCodes.FORBIDDEN
|
||||
? dispatch('receiveTraceUnauthorizedError')
|
||||
: dispatch('receiveTraceError'),
|
||||
);
|
||||
.catch((e) => {
|
||||
if (e.response.status === httpStatusCodes.FORBIDDEN) {
|
||||
dispatch('receiveTraceUnauthorizedError');
|
||||
} else {
|
||||
reportToSentry('job_actions', e);
|
||||
dispatch('receiveTraceError');
|
||||
}
|
||||
});
|
||||
|
||||
export const startPollingTrace = ({ dispatch, commit }) => {
|
||||
const traceTimeout = setTimeout(() => {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import * as Sentry from '@sentry/browser';
|
||||
|
||||
/**
|
||||
* capture anything starting with http:// or https://
|
||||
* https?:\/\/
|
||||
|
@ -10,3 +12,10 @@
|
|||
*/
|
||||
export const linkRegex = /(https?:\/\/[^"<>()\\^`{|}\s]+[^"<>()\\^`{|}\s.,:;!?])/g;
|
||||
export default { linkRegex };
|
||||
|
||||
export const reportToSentry = (component, failureType) => {
|
||||
Sentry.withScope((scope) => {
|
||||
scope.setTag('component', component);
|
||||
Sentry.captureException(failureType);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import { TrackingActions, TrackingLabels } from '~/packages/details/constants';
|
||||
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
|
||||
import {
|
||||
TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
|
||||
TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
|
||||
TRACKING_LABEL_CODE_INSTRUCTION,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
export default {
|
||||
|
@ -14,9 +17,25 @@ export default {
|
|||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
inject: ['composerHelpPath', 'composerConfigRepositoryName', 'composerPath', 'groupListUrl'],
|
||||
props: {
|
||||
packageEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['composerHelpPath']),
|
||||
...mapGetters(['composerRegistryInclude', 'composerPackageInclude', 'groupExists']),
|
||||
composerRegistryInclude() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `composer config repositories.${this.composerConfigRepositoryName} '{"type": "composer", "url": "${this.composerPath}"}'`;
|
||||
},
|
||||
composerPackageInclude() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `composer req ${[this.packageEntity.name]}:${this.packageEntity.version}`;
|
||||
},
|
||||
groupExists() {
|
||||
return this.groupListUrl?.length > 0;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
registryInclude: s__('PackageRegistry|Add composer registry'),
|
||||
|
@ -27,8 +46,11 @@ export default {
|
|||
'PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
tracking: {
|
||||
TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
|
||||
TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
|
||||
TRACKING_LABEL_CODE_INSTRUCTION,
|
||||
},
|
||||
installOptions: [{ value: 'composer', label: s__('PackageRegistry|Show Composer commands') }],
|
||||
};
|
||||
</script>
|
||||
|
@ -41,8 +63,8 @@ export default {
|
|||
:label="$options.i18n.registryInclude"
|
||||
:instruction="composerRegistryInclude"
|
||||
:copy-text="$options.i18n.copyRegistryInclude"
|
||||
:tracking-action="$options.trackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
data-testid="registry-include"
|
||||
/>
|
||||
|
||||
|
@ -50,8 +72,8 @@ export default {
|
|||
:label="$options.i18n.packageInclude"
|
||||
:instruction="composerPackageInclude"
|
||||
:copy-text="$options.i18n.copyPackageInclude"
|
||||
:tracking-action="$options.trackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
data-testid="package-include"
|
||||
/>
|
||||
<span data-testid="help-text">
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import { TrackingActions, TrackingLabels } from '~/packages/details/constants';
|
||||
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
|
||||
import {
|
||||
TRACKING_ACTION_COPY_CONAN_COMMAND,
|
||||
TRACKING_ACTION_COPY_CONAN_SETUP_COMMAND,
|
||||
TRACKING_LABEL_CODE_INSTRUCTION,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
export default {
|
||||
|
@ -14,17 +17,34 @@ export default {
|
|||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
inject: ['conanHelpPath', 'conanPath'],
|
||||
props: {
|
||||
packageEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['conanHelpPath']),
|
||||
...mapGetters(['conanInstallationCommand', 'conanSetupCommand']),
|
||||
conanInstallationCommand() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `conan install ${this.packageEntity.name} --remote=gitlab`;
|
||||
},
|
||||
conanSetupCommand() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `conan remote add gitlab ${this.conanPath}`;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
helpText: s__(
|
||||
'PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
tracking: {
|
||||
TRACKING_ACTION_COPY_CONAN_COMMAND,
|
||||
TRACKING_ACTION_COPY_CONAN_SETUP_COMMAND,
|
||||
TRACKING_LABEL_CODE_INSTRUCTION,
|
||||
},
|
||||
|
||||
installOptions: [{ value: 'conan', label: s__('PackageRegistry|Show Conan commands') }],
|
||||
};
|
||||
</script>
|
||||
|
@ -37,8 +57,8 @@ export default {
|
|||
:label="s__('PackageRegistry|Conan Command')"
|
||||
:instruction="conanInstallationCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Conan Command')"
|
||||
:tracking-action="$options.trackingActions.COPY_CONAN_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_CONAN_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
|
||||
|
@ -47,8 +67,8 @@ export default {
|
|||
:label="s__('PackageRegistry|Add Conan Remote')"
|
||||
:instruction="conanSetupCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Conan Setup Command')"
|
||||
:tracking-action="$options.trackingActions.COPY_CONAN_SETUP_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_CONAN_SETUP_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
/>
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
<template #link="{ content }">
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
<script>
|
||||
import { PackageType, TERRAFORM_PACKAGE_TYPE } from '~/packages/shared/constants';
|
||||
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
|
||||
import {
|
||||
PACKAGE_TYPE_CONAN,
|
||||
PACKAGE_TYPE_MAVEN,
|
||||
PACKAGE_TYPE_NPM,
|
||||
PACKAGE_TYPE_NUGET,
|
||||
PACKAGE_TYPE_PYPI,
|
||||
PACKAGE_TYPE_COMPOSER,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
import ComposerInstallation from './composer_installation.vue';
|
||||
import ConanInstallation from './conan_installation.vue';
|
||||
import MavenInstallation from './maven_installation.vue';
|
||||
|
@ -11,33 +17,22 @@ import PypiInstallation from './pypi_installation.vue';
|
|||
export default {
|
||||
name: 'InstallationCommands',
|
||||
components: {
|
||||
[PackageType.CONAN]: ConanInstallation,
|
||||
[PackageType.MAVEN]: MavenInstallation,
|
||||
[PackageType.NPM]: NpmInstallation,
|
||||
[PackageType.NUGET]: NugetInstallation,
|
||||
[PackageType.PYPI]: PypiInstallation,
|
||||
[PackageType.COMPOSER]: ComposerInstallation,
|
||||
[TERRAFORM_PACKAGE_TYPE]: TerraformInstallation,
|
||||
[PACKAGE_TYPE_CONAN]: ConanInstallation,
|
||||
[PACKAGE_TYPE_MAVEN]: MavenInstallation,
|
||||
[PACKAGE_TYPE_NPM]: NpmInstallation,
|
||||
[PACKAGE_TYPE_NUGET]: NugetInstallation,
|
||||
[PACKAGE_TYPE_PYPI]: PypiInstallation,
|
||||
[PACKAGE_TYPE_COMPOSER]: ComposerInstallation,
|
||||
},
|
||||
props: {
|
||||
packageEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
npmPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
npmHelpPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
installationComponent() {
|
||||
return this.$options.components[this.packageEntity.package_type];
|
||||
return this.$options.components[this.packageEntity.packageType];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -45,11 +40,6 @@ export default {
|
|||
|
||||
<template>
|
||||
<div v-if="installationComponent">
|
||||
<component
|
||||
:is="installationComponent"
|
||||
:name="packageEntity.name"
|
||||
:registry-url="npmPath"
|
||||
:help-url="npmHelpPath"
|
||||
/>
|
||||
<component :is="installationComponent" :package-entity="packageEntity" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import { TrackingActions, TrackingLabels } from '~/packages/details/constants';
|
||||
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
|
||||
import {
|
||||
TRACKING_ACTION_COPY_MAVEN_XML,
|
||||
TRACKING_ACTION_COPY_MAVEN_COMMAND,
|
||||
TRACKING_ACTION_COPY_MAVEN_SETUP,
|
||||
TRACKING_ACTION_COPY_GRADLE_INSTALL_COMMAND,
|
||||
TRACKING_ACTION_COPY_GRADLE_ADD_TO_SOURCE_COMMAND,
|
||||
TRACKING_ACTION_COPY_KOTLIN_INSTALL_COMMAND,
|
||||
TRACKING_ACTION_COPY_KOTLIN_ADD_TO_SOURCE_COMMAND,
|
||||
TRACKING_LABEL_CODE_INSTRUCTION,
|
||||
TRACKING_LABEL_MAVEN_INSTALLATION,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
export default {
|
||||
|
@ -14,22 +23,80 @@ export default {
|
|||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
inject: ['mavenHelpPath', 'mavenPath'],
|
||||
props: {
|
||||
packageEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
instructionType: 'maven',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['mavenHelpPath']),
|
||||
...mapGetters([
|
||||
'mavenInstallationXml',
|
||||
'mavenInstallationCommand',
|
||||
'mavenSetupXml',
|
||||
'gradleGroovyInstalCommand',
|
||||
'gradleGroovyAddSourceCommand',
|
||||
'gradleKotlinInstalCommand',
|
||||
'gradleKotlinAddSourceCommand',
|
||||
]),
|
||||
appGroup() {
|
||||
return this.packageEntity.metadata.appGroup;
|
||||
},
|
||||
appName() {
|
||||
return this.packageEntity.metadata.appName;
|
||||
},
|
||||
appVersion() {
|
||||
return this.packageEntity.metadata.appVersion;
|
||||
},
|
||||
mavenInstallationXml() {
|
||||
return `<dependency>
|
||||
<groupId>${this.appGroup}</groupId>
|
||||
<artifactId>${this.appName}</artifactId>
|
||||
<version>${this.appVersion}</version>
|
||||
</dependency>`;
|
||||
},
|
||||
|
||||
mavenInstallationCommand() {
|
||||
return `mvn dependency:get -Dartifact=${this.appGroup}:${this.appName}:${this.appVersion}`;
|
||||
},
|
||||
|
||||
mavenSetupXml() {
|
||||
return `<repositories>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>${this.mavenPath}</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>${this.mavenPath}</url>
|
||||
</repository>
|
||||
|
||||
<snapshotRepository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>${this.mavenPath}</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>`;
|
||||
},
|
||||
|
||||
gradleGroovyInstalCommand() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `implementation '${this.appGroup}:${this.appName}:${this.appVersion}'`;
|
||||
},
|
||||
|
||||
gradleGroovyAddSourceCommand() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `maven {
|
||||
url '${this.mavenPath}'
|
||||
}`;
|
||||
},
|
||||
|
||||
gradleKotlinInstalCommand() {
|
||||
return `implementation("${this.appGroup}:${this.appName}:${this.appVersion}")`;
|
||||
},
|
||||
|
||||
gradleKotlinAddSourceCommand() {
|
||||
return `maven("${this.mavenPath}")`;
|
||||
},
|
||||
showMaven() {
|
||||
return this.instructionType === 'maven';
|
||||
},
|
||||
|
@ -48,8 +115,18 @@ export default {
|
|||
'PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
tracking: {
|
||||
TRACKING_ACTION_COPY_MAVEN_XML,
|
||||
TRACKING_ACTION_COPY_MAVEN_COMMAND,
|
||||
TRACKING_ACTION_COPY_MAVEN_SETUP,
|
||||
TRACKING_ACTION_COPY_GRADLE_INSTALL_COMMAND,
|
||||
TRACKING_ACTION_COPY_GRADLE_ADD_TO_SOURCE_COMMAND,
|
||||
TRACKING_ACTION_COPY_KOTLIN_INSTALL_COMMAND,
|
||||
TRACKING_ACTION_COPY_KOTLIN_ADD_TO_SOURCE_COMMAND,
|
||||
TRACKING_LABEL_CODE_INSTRUCTION,
|
||||
TRACKING_LABEL_MAVEN_INSTALLATION,
|
||||
},
|
||||
|
||||
installOptions: [
|
||||
{ value: 'maven', label: s__('PackageRegistry|Maven XML') },
|
||||
{ value: 'groovy', label: s__('PackageRegistry|Gradle Groovy DSL') },
|
||||
|
@ -78,8 +155,8 @@ export default {
|
|||
<code-instruction
|
||||
:instruction="mavenInstallationXml"
|
||||
:copy-text="s__('PackageRegistry|Copy Maven XML')"
|
||||
:tracking-action="$options.trackingActions.COPY_MAVEN_XML"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_MAVEN_XML"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
|
||||
|
@ -87,8 +164,8 @@ export default {
|
|||
:label="s__('PackageRegistry|Maven Command')"
|
||||
:instruction="mavenInstallationCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Maven command')"
|
||||
:tracking-action="$options.trackingActions.COPY_MAVEN_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_MAVEN_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<h3 class="gl-font-lg">{{ s__('PackageRegistry|Registry setup') }}</h3>
|
||||
|
@ -102,8 +179,8 @@ export default {
|
|||
<code-instruction
|
||||
:instruction="mavenSetupXml"
|
||||
:copy-text="s__('PackageRegistry|Copy Maven registry XML')"
|
||||
:tracking-action="$options.trackingActions.COPY_MAVEN_SETUP"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_MAVEN_SETUP"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
|
@ -118,15 +195,15 @@ export default {
|
|||
:label="s__('PackageRegistry|Gradle Groovy DSL install command')"
|
||||
:instruction="gradleGroovyInstalCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Gradle Groovy DSL install command')"
|
||||
:tracking-action="$options.trackingActions.COPY_GRADLE_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_GRADLE_INSTALL_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
/>
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Add Gradle Groovy DSL repository command')"
|
||||
:instruction="gradleGroovyAddSourceCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy add Gradle Groovy DSL repository command')"
|
||||
:tracking-action="$options.trackingActions.COPY_GRADLE_ADD_TO_SOURCE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_GRADLE_ADD_TO_SOURCE_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
</template>
|
||||
|
@ -136,15 +213,15 @@ export default {
|
|||
:label="s__('PackageRegistry|Gradle Kotlin DSL install command')"
|
||||
:instruction="gradleKotlinInstalCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Gradle Kotlin DSL install command')"
|
||||
:tracking-action="$options.trackingActions.COPY_KOTLIN_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_KOTLIN_INSTALL_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
/>
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Add Gradle Kotlin DSL repository command')"
|
||||
:instruction="gradleKotlinAddSourceCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy add Gradle Kotlin DSL repository command')"
|
||||
:tracking-action="$options.trackingActions.COPY_KOTLIN_ADD_TO_SOURCE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_KOTLIN_ADD_TO_SOURCE_COMMAND"
|
||||
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,7 +10,6 @@ export const PACKAGE_TYPE_RUBYGEMS = 'RUBYGEMS';
|
|||
export const PACKAGE_TYPE_GENERIC = 'GENERIC';
|
||||
export const PACKAGE_TYPE_DEBIAN = 'DEBIAN';
|
||||
export const PACKAGE_TYPE_HELM = 'HELM';
|
||||
export const PACKAGE_TYPE_TERRAFORM = 'terraform_module';
|
||||
|
||||
export const DELETE_PACKAGE_TRACKING_ACTION = 'delete_package';
|
||||
export const REQUEST_DELETE_PACKAGE_TRACKING_ACTION = 'request_delete_package';
|
||||
|
@ -20,6 +19,46 @@ export const DELETE_PACKAGE_FILE_TRACKING_ACTION = 'delete_package_file';
|
|||
export const REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION = 'request_delete_package_file';
|
||||
export const CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION = 'cancel_delete_package_file';
|
||||
|
||||
export const TRACKING_LABEL_CODE_INSTRUCTION = 'code_instruction';
|
||||
export const TRACKING_LABEL_CONAN_INSTALLATION = 'conan_installation';
|
||||
export const TRACKING_LABEL_MAVEN_INSTALLATION = 'maven_installation';
|
||||
export const TRACKING_LABEL_NPM_INSTALLATION = 'npm_installation';
|
||||
export const TRACKING_LABEL_NUGET_INSTALLATION = 'nuget_installation';
|
||||
export const TRACKING_LABEL_PYPI_INSTALLATION = 'pypi_installation';
|
||||
export const TRACKING_LABEL_COMPOSER_INSTALLATION = 'composer_installation';
|
||||
|
||||
export const TRACKING_ACTION_INSTALLATION = 'installation';
|
||||
export const TRACKING_ACTION_REGISTRY_SETUP = 'registry_setup';
|
||||
|
||||
export const TRACKING_ACTION_COPY_CONAN_COMMAND = 'copy_conan_command';
|
||||
export const TRACKING_ACTION_COPY_CONAN_SETUP_COMMAND = 'copy_conan_setup_command';
|
||||
|
||||
export const TRACKING_ACTION_COPY_MAVEN_XML = 'copy_maven_xml';
|
||||
export const TRACKING_ACTION_COPY_MAVEN_COMMAND = 'copy_maven_command';
|
||||
export const TRACKING_ACTION_COPY_MAVEN_SETUP = 'copy_maven_setup_xml';
|
||||
export const TRACKING_ACTION_COPY_GRADLE_INSTALL_COMMAND = 'copy_gradle_install_command';
|
||||
export const TRACKING_ACTION_COPY_GRADLE_ADD_TO_SOURCE_COMMAND =
|
||||
'copy_gradle_add_to_source_command';
|
||||
export const TRACKING_ACTION_COPY_KOTLIN_INSTALL_COMMAND = 'copy_kotlin_install_command';
|
||||
export const TRACKING_ACTION_COPY_KOTLIN_ADD_TO_SOURCE_COMMAND =
|
||||
'copy_kotlin_add_to_source_command';
|
||||
|
||||
export const TRACKING_ACTION_COPY_NPM_INSTALL_COMMAND = 'copy_npm_install_command';
|
||||
export const TRACKING_ACTION_COPY_NPM_SETUP_COMMAND = 'copy_npm_setup_command';
|
||||
export const TRACKING_ACTION_COPY_YARN_INSTALL_COMMAND = 'copy_yarn_install_command';
|
||||
export const TRACKING_ACTION_COPY_YARN_SETUP_COMMAND = 'copy_yarn_setup_command';
|
||||
|
||||
export const TRACKING_ACTION_COPY_NUGET_INSTALL_COMMAND = 'copy_nuget_install_command';
|
||||
export const TRACKING_ACTION_COPY_NUGET_SETUP_COMMAND = 'copy_nuget_setup_command';
|
||||
|
||||
export const TRACKING_ACTION_COPY_PIP_INSTALL_COMMAND = 'copy_pip_install_command';
|
||||
export const TRACKING_ACTION_COPY_PYPI_SETUP_COMMAND = 'copy_pypi_setup_command';
|
||||
|
||||
export const TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND =
|
||||
'copy_composer_registry_include_command';
|
||||
export const TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND =
|
||||
'copy_composer_package_include_command';
|
||||
|
||||
export const TrackingCategories = {
|
||||
[PACKAGE_TYPE_MAVEN]: 'MavenPackages',
|
||||
[PACKAGE_TYPE_NPM]: 'NpmPackages',
|
||||
|
|
|
@ -7,6 +7,7 @@ import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
|||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants';
|
||||
import DismissPipelineGraphCallout from '../../graphql/mutations/dismiss_pipeline_notification.graphql';
|
||||
import getPipelineQuery from '../../graphql/queries/get_pipeline_header_data.query.graphql';
|
||||
import { reportToSentry, reportMessageToSentry } from '../../utils';
|
||||
import { listByLayers } from '../parsing_utils';
|
||||
import { IID_FAILURE, LAYER_VIEW, STAGE_VIEW, VIEW_TYPE_KEY } from './constants';
|
||||
|
@ -51,6 +52,7 @@ export default {
|
|||
alertType: null,
|
||||
callouts: [],
|
||||
currentViewType: STAGE_VIEW,
|
||||
canRefetchHeaderPipeline: false,
|
||||
pipeline: null,
|
||||
pipelineLayers: null,
|
||||
showAlert: false,
|
||||
|
@ -78,6 +80,26 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
headerPipeline: {
|
||||
query: getPipelineQuery,
|
||||
// this query is already being called in header_component.vue, which shares the same cache as this component
|
||||
// the skip here is to prevent sending double network requests on page load
|
||||
skip() {
|
||||
return !this.canRefetchHeaderPipeline;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.pipelineProjectPath,
|
||||
iid: this.pipelineIid,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.project?.pipeline || {};
|
||||
},
|
||||
error() {
|
||||
this.reportFailure({ type: LOAD_FAILURE, skipSentry: true });
|
||||
},
|
||||
},
|
||||
pipeline: {
|
||||
context() {
|
||||
return getQueryHeaders(this.graphqlResourceEtag);
|
||||
|
@ -217,6 +239,10 @@ export default {
|
|||
},
|
||||
refreshPipelineGraph() {
|
||||
this.$apollo.queries.pipeline.refetch();
|
||||
|
||||
// this will update the status in header_component since they share the same cache
|
||||
this.canRefetchHeaderPipeline = true;
|
||||
this.$apollo.queries.headerPipeline.refetch();
|
||||
},
|
||||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
reportFailure({ type, err = 'No error string passed.', skipSentry = false }) {
|
||||
|
|
|
@ -143,13 +143,6 @@ export default {
|
|||
return cancelable && userPermissions.updatePipeline;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isFinished(finished) {
|
||||
if (finished) {
|
||||
this.$apollo.queries.pipeline.stopPolling();
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
reportFailure(errorType) {
|
||||
this.failureType = errorType;
|
||||
|
@ -218,7 +211,7 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="pipeline-header-container">
|
||||
<div class="js-pipeline-header-container">
|
||||
<gl-alert v-if="hasError" :variant="failure.variant">{{ failure.text }}</gl-alert>
|
||||
<ci-header
|
||||
v-if="shouldRenderContent"
|
||||
|
|
|
@ -54,6 +54,8 @@ class ProjectsController < Projects::ApplicationController
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def new
|
||||
return access_denied! unless current_user.can_create_project?
|
||||
|
||||
@namespace = Namespace.find_by(id: params[:namespace_id]) if params[:namespace_id]
|
||||
return access_denied! if @namespace && !can?(current_user, :create_projects, @namespace)
|
||||
|
||||
|
|
47
app/graphql/resolvers/paginated_tree_resolver.rb
Normal file
47
app/graphql/resolvers/paginated_tree_resolver.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
class PaginatedTreeResolver < BaseResolver
|
||||
type Types::Tree::TreeType.connection_type, null: true
|
||||
extension Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension
|
||||
|
||||
calls_gitaly!
|
||||
|
||||
argument :path, GraphQL::Types::String,
|
||||
required: false,
|
||||
default_value: '', # root of the repository
|
||||
description: 'The path to get the tree for. Default value is the root of the repository.'
|
||||
argument :ref, GraphQL::Types::String,
|
||||
required: false,
|
||||
default_value: :head,
|
||||
description: 'The commit ref to get the tree for. Default value is HEAD.'
|
||||
argument :recursive, GraphQL::Types::Boolean,
|
||||
required: false,
|
||||
default_value: false,
|
||||
description: 'Used to get a recursive tree. Default is false.'
|
||||
|
||||
alias_method :repository, :object
|
||||
|
||||
def resolve(**args)
|
||||
return unless repository.exists?
|
||||
|
||||
cursor = args.delete(:after)
|
||||
|
||||
pagination_params = {
|
||||
limit: @field.max_page_size || 100,
|
||||
page_token: cursor
|
||||
}
|
||||
|
||||
tree = repository.tree(args[:ref], args[:path], recursive: args[:recursive], pagination_params: pagination_params)
|
||||
|
||||
next_cursor = tree.cursor&.next_cursor
|
||||
Gitlab::Graphql::ExternallyPaginatedArray.new(cursor, next_cursor, *tree)
|
||||
rescue Gitlab::Git::CommandError => e
|
||||
raise Gitlab::Graphql::Errors::ArgumentError, e
|
||||
end
|
||||
|
||||
def self.field_options
|
||||
super.merge(connection: false) # we manage the pagination manually, so opt out of the connection field extension
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,6 +14,10 @@ module Types
|
|||
description: 'Indicates a corresponding Git repository exists on disk.'
|
||||
field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true,
|
||||
description: 'Tree of the repository.'
|
||||
field :paginated_tree, Types::Tree::TreeType.connection_type, null: true, resolver: Resolvers::PaginatedTreeResolver, calls_gitaly: true,
|
||||
max_page_size: 100,
|
||||
description: 'Paginated tree of the repository.',
|
||||
feature_flag: :paginated_tree_graphql_query
|
||||
field :blobs, Types::Repository::BlobType.connection_type, null: true, resolver: Resolvers::BlobsResolver, calls_gitaly: true,
|
||||
description: 'Blobs contained within the repository'
|
||||
field :branch_names, [GraphQL::Types::String], null: true, calls_gitaly: true,
|
||||
|
|
|
@ -267,7 +267,11 @@ module Nav
|
|||
builder.add_primary_menu_item(id: 'your', title: _('Your projects'), href: dashboard_projects_path)
|
||||
builder.add_primary_menu_item(id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path)
|
||||
builder.add_primary_menu_item(id: 'explore', title: _('Explore projects'), href: explore_root_path)
|
||||
builder.add_secondary_menu_item(id: 'create', title: _('Create new project'), href: new_project_path)
|
||||
|
||||
if current_user.can_create_project?
|
||||
builder.add_secondary_menu_item(id: 'create', title: _('Create new project'), href: new_project_path)
|
||||
end
|
||||
|
||||
builder.build
|
||||
end
|
||||
|
||||
|
|
|
@ -527,6 +527,12 @@ class IssuableBaseService < ::BaseProjectService
|
|||
def allowed_update_params(params)
|
||||
params
|
||||
end
|
||||
|
||||
def update_issuable_sla(issuable)
|
||||
return unless issuable_sla = issuable.issuable_sla
|
||||
|
||||
issuable_sla.update(issuable_closed: issuable.closed?)
|
||||
end
|
||||
end
|
||||
|
||||
IssuableBaseService.prepend_mod_with('IssuableBaseService')
|
||||
|
|
|
@ -32,7 +32,7 @@ module Issues
|
|||
|
||||
notification_service.async.close_issue(issue, current_user, { closed_via: closed_via }) if notifications
|
||||
todo_service.close_issue(issue, current_user)
|
||||
resolve_alert(issue)
|
||||
perform_incident_management_actions(issue)
|
||||
execute_hooks(issue, 'close')
|
||||
invalidate_cache_counts(issue, users: issue.assignees)
|
||||
issue.update_project_counter_caches
|
||||
|
@ -51,6 +51,10 @@ module Issues
|
|||
|
||||
private
|
||||
|
||||
def perform_incident_management_actions(issue)
|
||||
resolve_alert(issue)
|
||||
end
|
||||
|
||||
def close_external_issue(issue, closed_via)
|
||||
return unless project.external_issue_tracker&.support_close_issue?
|
||||
|
||||
|
@ -89,3 +93,5 @@ module Issues
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Issues::CloseService.prepend_mod_with('Issues::CloseService')
|
||||
|
|
|
@ -9,6 +9,7 @@ module Issues
|
|||
event_service.reopen_issue(issue, current_user)
|
||||
create_note(issue, 'reopened')
|
||||
notification_service.async.reopen_issue(issue, current_user)
|
||||
perform_incident_management_actions(issue)
|
||||
execute_hooks(issue, 'reopen')
|
||||
invalidate_cache_counts(issue, users: issue.assignees)
|
||||
issue.update_project_counter_caches
|
||||
|
@ -21,8 +22,13 @@ module Issues
|
|||
|
||||
private
|
||||
|
||||
def perform_incident_management_actions(issue)
|
||||
end
|
||||
|
||||
def create_note(issue, state = issue.state)
|
||||
SystemNoteService.change_status(issue, issue.project, current_user, state, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Issues::ReopenService.prepend_mod_with('Issues::ReopenService')
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Allow rendering of PlantUML diagrams in Asciidoc documents.')
|
||||
= _('Render diagrams in your documents using PlantUML.')
|
||||
= link_to _('Learn more.'), help_page_path('administration/integration/plantuml.md'), target: '_blank', rel: 'noopener noreferrer'
|
||||
.settings-content
|
||||
= form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-plantuml-settings'), html: { class: 'fieldset-form', id: 'plantuml-settings' } do |f|
|
||||
= form_errors(@application_setting) if expanded
|
||||
|
@ -20,8 +21,6 @@
|
|||
= f.label :plantuml_url, _('PlantUML URL'), class: 'label-bold'
|
||||
= f.text_field :plantuml_url, class: 'form-control gl-form-input', placeholder: 'http://your-plantuml-instance:8080'
|
||||
.form-text.text-muted
|
||||
Allow rendering of
|
||||
= link_to "PlantUML", "http://plantuml.com"
|
||||
diagrams in Asciidoc documents using an external PlantUML service.
|
||||
= _('The hostname of your PlantUML server.')
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: paginated_tree_graphql_query
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66751
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337214
|
||||
milestone: '14.2'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
ci_db_config = Gitlab::Application.config.database_configuration[Rails.env]["ci"]
|
||||
|
||||
if ci_db_config.present?
|
||||
raise "migrations_paths setting for ci database must be `db/ci_migrate`" unless ci_db_config["migrations_paths"] == 'db/ci_migrate'
|
||||
end
|
1
db/ci_migrate
Symbolic link
1
db/ci_migrate
Symbolic link
|
@ -0,0 +1 @@
|
|||
migrate
|
|
@ -1,31 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateCiInstanceVariablesOnCi < ActiveRecord::Migration[6.1]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
unless table_exists?(:ci_instance_variables)
|
||||
create_table :ci_instance_variables do |t|
|
||||
t.integer :variable_type, null: false, limit: 2, default: 1
|
||||
t.boolean :masked, default: false, allow_null: false
|
||||
t.boolean :protected, default: false, allow_null: false
|
||||
t.text :key, null: false
|
||||
t.text :encrypted_value
|
||||
t.text :encrypted_value_iv
|
||||
|
||||
t.index [:key], name: 'index_ci_instance_variables_on_key', unique: true, using: :btree
|
||||
end
|
||||
end
|
||||
|
||||
add_text_limit(:ci_instance_variables, :key, 255)
|
||||
# Use constraint_name generated from db/migrate/20200625193358_increase_size_on_instance_level_variable_values.rb
|
||||
add_text_limit(:ci_instance_variables, :encrypted_value, 13_579, constraint_name: 'check_956afd70f1')
|
||||
add_text_limit(:ci_instance_variables, :encrypted_value_iv, 255)
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :ci_instance_variables
|
||||
end
|
||||
end
|
|
@ -1 +0,0 @@
|
|||
1b74312f59f6f8937cd0dd754d22dc72e9bdc7302e6254a2fda5762afebe303c
|
|
@ -1,45 +0,0 @@
|
|||
CREATE TABLE ar_internal_metadata (
|
||||
key character varying NOT NULL,
|
||||
value character varying,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE ci_instance_variables (
|
||||
id bigint NOT NULL,
|
||||
variable_type smallint DEFAULT 1 NOT NULL,
|
||||
masked boolean DEFAULT false,
|
||||
protected boolean DEFAULT false,
|
||||
key text NOT NULL,
|
||||
encrypted_value text,
|
||||
encrypted_value_iv text,
|
||||
CONSTRAINT check_07a45a5bcb CHECK ((char_length(encrypted_value_iv) <= 255)),
|
||||
CONSTRAINT check_5aede12208 CHECK ((char_length(key) <= 255)),
|
||||
CONSTRAINT check_956afd70f1 CHECK ((char_length(encrypted_value) <= 13579))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ci_instance_variables_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE ci_instance_variables_id_seq OWNED BY ci_instance_variables.id;
|
||||
|
||||
CREATE TABLE schema_migrations (
|
||||
version character varying NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE ONLY ci_instance_variables ALTER COLUMN id SET DEFAULT nextval('ci_instance_variables_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY ar_internal_metadata
|
||||
ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key);
|
||||
|
||||
ALTER TABLE ONLY ci_instance_variables
|
||||
ADD CONSTRAINT ci_instance_variables_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY schema_migrations
|
||||
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
|
||||
|
||||
CREATE UNIQUE INDEX index_ci_instance_variables_on_key ON ci_instance_variables USING btree (key);
|
1
db/ci_structure.sql
Symbolic link
1
db/ci_structure.sql
Symbolic link
|
@ -0,0 +1 @@
|
|||
structure.sql
|
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddLabelAppliedIssuableClosedToIssuableSla < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :issuable_slas, :label_applied, :boolean, default: false, null: false
|
||||
add_column :issuable_slas, :issuable_closed, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexForLabelAppliedToIssuableSla < ActiveRecord::Migration[6.1]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAME = 'index_issuable_slas_on_due_at_id_label_applied_issuable_closed'
|
||||
|
||||
def up
|
||||
add_concurrent_index :issuable_slas, [:due_at, :id], name: INDEX_NAME, where: 'label_applied = FALSE AND issuable_closed = FALSE'
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :issuable_slas, INDEX_NAME
|
||||
end
|
||||
end
|
18
db/migrate/20210729123101_confirm_security_bot.rb
Normal file
18
db/migrate/20210729123101_confirm_security_bot.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ConfirmSecurityBot < ActiveRecord::Migration[6.0]
|
||||
class User < ActiveRecord::Base
|
||||
self.table_name = 'users'
|
||||
SECURITY_BOT_TYPE = 8
|
||||
end
|
||||
|
||||
def up
|
||||
User.where(user_type: User::SECURITY_BOT_TYPE, confirmed_at: nil)
|
||||
.update_all(confirmed_at: Time.current)
|
||||
end
|
||||
|
||||
# no-op
|
||||
# Security Bot should be always confirmed
|
||||
def down
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UpdateIssuableSlasWhereIssueClosed < ActiveRecord::Migration[6.1]
|
||||
ISSUE_CLOSED_STATUS = 2
|
||||
|
||||
class IssuableSla < ActiveRecord::Base
|
||||
include EachBatch
|
||||
|
||||
self.table_name = 'issuable_slas'
|
||||
|
||||
belongs_to :issue, class_name: 'Issue'
|
||||
end
|
||||
|
||||
class Issue < ActiveRecord::Base
|
||||
self.table_name = 'issues'
|
||||
|
||||
has_one :issuable_sla, class_name: 'IssuableSla'
|
||||
end
|
||||
|
||||
def up
|
||||
IssuableSla.each_batch(of: 50) do |relation|
|
||||
relation.joins(:issue)
|
||||
.where(issues: { state_id: ISSUE_CLOSED_STATUS } )
|
||||
.update_all(issuable_closed: true)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
1
db/schema_migrations/20210712052519
Normal file
1
db/schema_migrations/20210712052519
Normal file
|
@ -0,0 +1 @@
|
|||
f3959b7a6f7ac95019f2f85c6383ddd11294562e94936ef3b5704bd4de7c5910
|
1
db/schema_migrations/20210714043818
Normal file
1
db/schema_migrations/20210714043818
Normal file
|
@ -0,0 +1 @@
|
|||
344736284dc18b5f7516ec2062bef99b2444ae31720691e56b4e8687d5566b31
|
1
db/schema_migrations/20210722042939
Normal file
1
db/schema_migrations/20210722042939
Normal file
|
@ -0,0 +1 @@
|
|||
dd3b35b87c2f015895d807ede2521c9672fb41ec7a3b0b1a2f7abdc009950b6e
|
1
db/schema_migrations/20210729123101
Normal file
1
db/schema_migrations/20210729123101
Normal file
|
@ -0,0 +1 @@
|
|||
8522eaf951d87de04aea82fe8e1a9577e6665c8d08245282239476e49b02bc7d
|
|
@ -14200,7 +14200,9 @@ ALTER SEQUENCE issuable_severities_id_seq OWNED BY issuable_severities.id;
|
|||
CREATE TABLE issuable_slas (
|
||||
id bigint NOT NULL,
|
||||
issue_id bigint NOT NULL,
|
||||
due_at timestamp with time zone NOT NULL
|
||||
due_at timestamp with time zone NOT NULL,
|
||||
label_applied boolean DEFAULT false NOT NULL,
|
||||
issuable_closed boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE issuable_slas_id_seq
|
||||
|
@ -24047,6 +24049,8 @@ CREATE INDEX index_issuable_metric_images_on_issue_id ON issuable_metric_images
|
|||
|
||||
CREATE UNIQUE INDEX index_issuable_severities_on_issue_id ON issuable_severities USING btree (issue_id);
|
||||
|
||||
CREATE INDEX index_issuable_slas_on_due_at_id_label_applied_issuable_closed ON issuable_slas USING btree (due_at, id) WHERE ((label_applied = false) AND (issuable_closed = false));
|
||||
|
||||
CREATE UNIQUE INDEX index_issuable_slas_on_issue_id ON issuable_slas USING btree (issue_id);
|
||||
|
||||
CREATE INDEX index_issue_assignees_on_user_id ON issue_assignees USING btree (user_id);
|
||||
|
|
|
@ -7039,6 +7039,29 @@ The edge type for [`Todo`](#todo).
|
|||
| <a id="todoedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="todoedgenode"></a>`node` | [`Todo`](#todo) | The item at the end of the edge. |
|
||||
|
||||
#### `TreeConnection`
|
||||
|
||||
The connection type for [`Tree`](#tree).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="treeconnectionedges"></a>`edges` | [`[TreeEdge]`](#treeedge) | A list of edges. |
|
||||
| <a id="treeconnectionnodes"></a>`nodes` | [`[Tree]`](#tree) | A list of nodes. |
|
||||
| <a id="treeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `TreeEdge`
|
||||
|
||||
The edge type for [`Tree`](#tree).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="treeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="treeedgenode"></a>`node` | [`Tree`](#tree) | The item at the end of the edge. |
|
||||
|
||||
#### `TreeEntryConnection`
|
||||
|
||||
The connection type for [`TreeEntry`](#treeentry).
|
||||
|
@ -12714,6 +12737,24 @@ Returns [`[String!]`](#string).
|
|||
| <a id="repositorybranchnamesoffset"></a>`offset` | [`Int!`](#int) | The number of branch names to skip. |
|
||||
| <a id="repositorybranchnamessearchpattern"></a>`searchPattern` | [`String!`](#string) | The pattern to search for branch names by. |
|
||||
|
||||
##### `Repository.paginatedTree`
|
||||
|
||||
Paginated tree of the repository. Available only when feature flag `paginated_tree_graphql_query` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice.
|
||||
|
||||
Returns [`TreeConnection`](#treeconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="repositorypaginatedtreepath"></a>`path` | [`String`](#string) | The path to get the tree for. Default value is the root of the repository. |
|
||||
| <a id="repositorypaginatedtreerecursive"></a>`recursive` | [`Boolean`](#boolean) | Used to get a recursive tree. Default is false. |
|
||||
| <a id="repositorypaginatedtreeref"></a>`ref` | [`String`](#string) | The commit ref to get the tree for. Default value is HEAD. |
|
||||
|
||||
##### `Repository.tree`
|
||||
|
||||
Tree of the repository.
|
||||
|
|
|
@ -61,7 +61,6 @@ development:
|
|||
adapter: postgresql
|
||||
encoding: unicode
|
||||
database: gitlabhq_development_ci
|
||||
migrations_paths: db/ci_migrate
|
||||
host: /path/to/gdk/postgresql
|
||||
pool: 10
|
||||
prepared_statements: false
|
||||
|
@ -82,7 +81,6 @@ test: &test
|
|||
adapter: postgresql
|
||||
encoding: unicode
|
||||
database: gitlabhq_test_ci
|
||||
migrations_paths: db/ci_migrate
|
||||
host: /path/to/gdk/postgresql
|
||||
pool: 10
|
||||
prepared_statements: false
|
||||
|
|
|
@ -133,7 +133,8 @@ To specify your pronouns:
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25742) in GitLab 14.2.
|
||||
|
||||
You can add your name pronunciation to your GitLab account. This will be displayed in your profile, below your name.
|
||||
You can add your name pronunciation to your GitLab account. This is displayed in your profile, below
|
||||
your name.
|
||||
|
||||
To add your name pronunciation:
|
||||
|
||||
|
|
|
@ -6,17 +6,14 @@ module Gitlab
|
|||
class Context
|
||||
attr_reader :connection
|
||||
|
||||
DEFAULT_SCHEMA_MIGRATIONS_PATH = "db/schema_migrations"
|
||||
|
||||
def initialize(connection)
|
||||
@connection = connection
|
||||
end
|
||||
|
||||
def schema_directory
|
||||
@schema_directory ||=
|
||||
if ActiveRecord::Base.configurations.primary?(database_name)
|
||||
File.join(db_dir, 'schema_migrations')
|
||||
else
|
||||
File.join(db_dir, "#{database_name}_schema_migrations")
|
||||
end
|
||||
@schema_directory ||= Rails.root.join(database_schema_migrations_path).to_s
|
||||
end
|
||||
|
||||
def versions_to_create
|
||||
|
@ -32,8 +29,8 @@ module Gitlab
|
|||
@database_name ||= @connection.pool.db_config.name
|
||||
end
|
||||
|
||||
def db_dir
|
||||
@db_dir ||= Rails.application.config.paths["db"].first
|
||||
def database_schema_migrations_path
|
||||
@connection.pool.db_config.configuration_hash[:schema_migrations_path] || DEFAULT_SCHEMA_MIGRATIONS_PATH
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module Gitlab
|
|||
module Docs
|
||||
class Renderer
|
||||
include Gitlab::Usage::Docs::Helper
|
||||
DICTIONARY_PATH = Rails.root.join('doc', 'development', 'usage_ping')
|
||||
DICTIONARY_PATH = Rails.root.join('doc', 'development', 'service_ping')
|
||||
TEMPLATE_PATH = Rails.root.join('lib', 'gitlab', 'usage', 'docs', 'templates', 'default.md.haml')
|
||||
|
||||
def initialize(metrics_definitions)
|
||||
|
|
|
@ -3342,9 +3342,6 @@ msgstr ""
|
|||
msgid "Allow public access to pipelines and job details, including output logs and artifacts."
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow rendering of PlantUML diagrams in Asciidoc documents."
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow requests to the local network from hooks and services."
|
||||
msgstr ""
|
||||
|
||||
|
@ -27724,6 +27721,9 @@ msgstr ""
|
|||
msgid "Rename/Move"
|
||||
msgstr ""
|
||||
|
||||
msgid "Render diagrams in your documents using PlantUML."
|
||||
msgstr ""
|
||||
|
||||
msgid "Renew subscription"
|
||||
msgstr ""
|
||||
|
||||
|
@ -33016,6 +33016,9 @@ msgstr ""
|
|||
msgid "The group_project_ids parameter is only allowed for a group"
|
||||
msgstr ""
|
||||
|
||||
msgid "The hostname of your PlantUML server."
|
||||
msgstr ""
|
||||
|
||||
msgid "The hostname of your Snowplow collector."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "1.208.0",
|
||||
"@gitlab/svgs": "1.209.0",
|
||||
"@gitlab/tributejs": "1.0.0",
|
||||
"@gitlab/ui": "32.0.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
|
|
|
@ -42,6 +42,32 @@ RSpec.describe ProjectsController do
|
|||
expect(response).not_to render_template('new')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an external user' do
|
||||
let_it_be(:user) { create(:user, external: true) }
|
||||
|
||||
it 'responds with status 404' do
|
||||
group.add_owner(user)
|
||||
|
||||
get :new, params: { namespace_id: group.id }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
expect(response).not_to render_template('new')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is a group guest' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
it 'responds with status 404' do
|
||||
group.add_guest(user)
|
||||
|
||||
get :new, params: { namespace_id: group.id }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
expect(response).not_to render_template('new')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -240,10 +240,14 @@ RSpec.describe 'Pipeline', :js do
|
|||
end
|
||||
end
|
||||
|
||||
it 'is possible to retry the success job' do
|
||||
it 'is possible to retry the success job', :sidekiq_might_not_need_inline do
|
||||
find('#ci-badge-build .ci-action-icon-container').click
|
||||
wait_for_requests
|
||||
|
||||
expect(page).not_to have_content('Retry job')
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_selector('.js-ci-status-icon-running')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -282,10 +286,14 @@ RSpec.describe 'Pipeline', :js do
|
|||
end
|
||||
end
|
||||
|
||||
it 'is possible to retry the failed build' do
|
||||
it 'is possible to retry the failed build', :sidekiq_might_not_need_inline do
|
||||
find('#ci-badge-test .ci-action-icon-container').click
|
||||
wait_for_requests
|
||||
|
||||
expect(page).not_to have_content('Retry job')
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_selector('.js-ci-status-icon-running')
|
||||
end
|
||||
end
|
||||
|
||||
it 'includes the failure reason' do
|
||||
|
@ -308,10 +316,14 @@ RSpec.describe 'Pipeline', :js do
|
|||
end
|
||||
end
|
||||
|
||||
it 'is possible to play the manual job' do
|
||||
it 'is possible to play the manual job', :sidekiq_might_not_need_inline do
|
||||
find('#ci-badge-manual-build .ci-action-icon-container').click
|
||||
wait_for_requests
|
||||
|
||||
expect(page).not_to have_content('Play job')
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_selector('.js-ci-status-icon-running')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -411,11 +423,18 @@ RSpec.describe 'Pipeline', :js do
|
|||
context 'when retrying' do
|
||||
before do
|
||||
find('[data-testid="retryPipeline"]').click
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do
|
||||
expect(page).not_to have_content('Retry')
|
||||
end
|
||||
|
||||
it 'shows running status in pipeline header', :sidekiq_might_not_need_inline do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_selector('.js-ci-status-icon-running')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -770,7 +789,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as created' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('pending')
|
||||
end
|
||||
|
||||
|
@ -795,7 +814,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as pending' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('running')
|
||||
end
|
||||
|
||||
|
@ -817,7 +836,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as created' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('pending')
|
||||
end
|
||||
|
||||
|
@ -842,7 +861,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as pending' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('running')
|
||||
end
|
||||
|
||||
|
@ -871,7 +890,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as waiting for resource' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('waiting')
|
||||
end
|
||||
|
||||
|
@ -893,7 +912,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as waiting for resource' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('waiting')
|
||||
end
|
||||
|
||||
|
@ -914,7 +933,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as pending' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('running')
|
||||
end
|
||||
|
||||
|
@ -936,7 +955,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as pending' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('running')
|
||||
end
|
||||
|
||||
|
@ -959,7 +978,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as waiting for resource' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('waiting')
|
||||
end
|
||||
|
||||
|
@ -981,7 +1000,7 @@ RSpec.describe 'Pipeline', :js do
|
|||
it 'shows deploy job as waiting for resource' do
|
||||
subject
|
||||
|
||||
within('.pipeline-header-container') do
|
||||
within('.js-pipeline-header-container') do
|
||||
expect(page).to have_content('waiting')
|
||||
end
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ exports[`ConanInstallation renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Conan Command"
|
||||
instruction="foo/command"
|
||||
instruction="conan install @gitlab-org/package-15 --remote=gitlab"
|
||||
label="Conan Command"
|
||||
trackingaction="copy_conan_command"
|
||||
trackinglabel="code_instruction"
|
||||
|
@ -23,7 +23,7 @@ exports[`ConanInstallation renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Conan Setup Command"
|
||||
instruction="foo/setup"
|
||||
instruction="conan remote add gitlab conanPath"
|
||||
label="Add Conan Remote"
|
||||
trackingaction="copy_conan_setup_command"
|
||||
trackinglabel="code_instruction"
|
||||
|
|
|
@ -10,7 +10,7 @@ exports[`MavenInstallation groovy renders all the messages 1`] = `
|
|||
<code-instruction-stub
|
||||
class="gl-mb-5"
|
||||
copytext="Copy Gradle Groovy DSL install command"
|
||||
instruction="foo/gradle/groovy/install"
|
||||
instruction="implementation 'appGroup:appName:appVersion'"
|
||||
label="Gradle Groovy DSL install command"
|
||||
trackingaction="copy_gradle_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
|
@ -18,7 +18,9 @@ exports[`MavenInstallation groovy renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy add Gradle Groovy DSL repository command"
|
||||
instruction="foo/gradle/groovy/add/source"
|
||||
instruction="maven {
|
||||
url 'mavenPath'
|
||||
}"
|
||||
label="Add Gradle Groovy DSL repository command"
|
||||
multiline="true"
|
||||
trackingaction="copy_gradle_add_to_source_command"
|
||||
|
@ -37,7 +39,7 @@ exports[`MavenInstallation kotlin renders all the messages 1`] = `
|
|||
<code-instruction-stub
|
||||
class="gl-mb-5"
|
||||
copytext="Copy Gradle Kotlin DSL install command"
|
||||
instruction="foo/gradle/kotlin/install"
|
||||
instruction="implementation(\\"appGroup:appName:appVersion\\")"
|
||||
label="Gradle Kotlin DSL install command"
|
||||
trackingaction="copy_kotlin_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
|
@ -45,7 +47,7 @@ exports[`MavenInstallation kotlin renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy add Gradle Kotlin DSL repository command"
|
||||
instruction="foo/gradle/kotlin/add/source"
|
||||
instruction="maven(\\"mavenPath\\")"
|
||||
label="Add Gradle Kotlin DSL repository command"
|
||||
multiline="true"
|
||||
trackingaction="copy_kotlin_add_to_source_command"
|
||||
|
@ -69,7 +71,11 @@ exports[`MavenInstallation maven renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Maven XML"
|
||||
instruction="foo/xml"
|
||||
instruction="<dependency>
|
||||
<groupId>appGroup</groupId>
|
||||
<artifactId>appName</artifactId>
|
||||
<version>appVersion</version>
|
||||
</dependency>"
|
||||
label=""
|
||||
multiline="true"
|
||||
trackingaction="copy_maven_xml"
|
||||
|
@ -78,7 +84,7 @@ exports[`MavenInstallation maven renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Maven command"
|
||||
instruction="foo/command"
|
||||
instruction="mvn dependency:get -Dartifact=appGroup:appName:appVersion"
|
||||
label="Maven Command"
|
||||
trackingaction="copy_maven_command"
|
||||
trackinglabel="code_instruction"
|
||||
|
@ -98,7 +104,24 @@ exports[`MavenInstallation maven renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Maven registry XML"
|
||||
instruction="foo/setup"
|
||||
instruction="<repositories>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>mavenPath</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>mavenPath</url>
|
||||
</repository>
|
||||
|
||||
<snapshotRepository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>mavenPath</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>"
|
||||
label=""
|
||||
multiline="true"
|
||||
trackingaction="copy_maven_setup_xml"
|
||||
|
|
|
@ -1,44 +1,35 @@
|
|||
import { GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as composerHelpPath } from 'jest/packages/details/mock_data';
|
||||
import { composerPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import { TrackingActions } from '~/packages/details/constants';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { packageData } from 'jest/packages_and_registries/package_registry/mock_data';
|
||||
import ComposerInstallation from '~/packages_and_registries/package_registry/components/details/composer_installation.vue';
|
||||
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
|
||||
import {
|
||||
TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
|
||||
TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
|
||||
PACKAGE_TYPE_COMPOSER,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
const packageEntity = { ...packageData(), packageType: PACKAGE_TYPE_COMPOSER };
|
||||
|
||||
describe('ComposerInstallation', () => {
|
||||
let wrapper;
|
||||
let store;
|
||||
|
||||
const composerRegistryIncludeStr = 'foo/registry';
|
||||
const composerPackageIncludeStr = 'foo/package';
|
||||
|
||||
const createStore = (groupExists = true) => {
|
||||
store = new Vuex.Store({
|
||||
state: { packageEntity, composerHelpPath },
|
||||
getters: {
|
||||
composerRegistryInclude: () => composerRegistryIncludeStr,
|
||||
composerPackageInclude: () => composerPackageIncludeStr,
|
||||
groupExists: () => groupExists,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findRootNode = () => wrapper.find('[data-testid="root-node"]');
|
||||
const findRegistryInclude = () => wrapper.find('[data-testid="registry-include"]');
|
||||
const findPackageInclude = () => wrapper.find('[data-testid="package-include"]');
|
||||
const findHelpText = () => wrapper.find('[data-testid="help-text"]');
|
||||
const findHelpLink = () => wrapper.find(GlLink);
|
||||
const findRootNode = () => wrapper.findByTestId('root-node');
|
||||
const findRegistryInclude = () => wrapper.findByTestId('registry-include');
|
||||
const findPackageInclude = () => wrapper.findByTestId('package-include');
|
||||
const findHelpText = () => wrapper.findByTestId('help-text');
|
||||
const findHelpLink = () => wrapper.findComponent(GlLink);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent() {
|
||||
wrapper = shallowMount(ComposerInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
function createComponent(groupListUrl = 'groupListUrl') {
|
||||
wrapper = shallowMountExtended(ComposerInstallation, {
|
||||
provide: {
|
||||
composerHelpPath: 'composerHelpPath',
|
||||
composerConfigRepositoryName: 'composerConfigRepositoryName',
|
||||
composerPath: 'composerPath',
|
||||
groupListUrl,
|
||||
},
|
||||
propsData: { packageEntity },
|
||||
stubs: {
|
||||
GlSprintf,
|
||||
},
|
||||
|
@ -51,7 +42,6 @@ describe('ComposerInstallation', () => {
|
|||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
createStore();
|
||||
createComponent();
|
||||
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
|
@ -64,7 +54,6 @@ describe('ComposerInstallation', () => {
|
|||
|
||||
describe('registry include command', () => {
|
||||
beforeEach(() => {
|
||||
createStore();
|
||||
createComponent();
|
||||
});
|
||||
|
||||
|
@ -72,9 +61,9 @@ describe('ComposerInstallation', () => {
|
|||
const registryIncludeCommand = findRegistryInclude();
|
||||
expect(registryIncludeCommand.exists()).toBe(true);
|
||||
expect(registryIncludeCommand.props()).toMatchObject({
|
||||
instruction: composerRegistryIncludeStr,
|
||||
instruction: `composer config repositories.composerConfigRepositoryName '{"type": "composer", "url": "composerPath"}'`,
|
||||
copyText: 'Copy registry include',
|
||||
trackingAction: TrackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -85,7 +74,6 @@ describe('ComposerInstallation', () => {
|
|||
|
||||
describe('package include command', () => {
|
||||
beforeEach(() => {
|
||||
createStore();
|
||||
createComponent();
|
||||
});
|
||||
|
||||
|
@ -93,9 +81,9 @@ describe('ComposerInstallation', () => {
|
|||
const registryIncludeCommand = findPackageInclude();
|
||||
expect(registryIncludeCommand.exists()).toBe(true);
|
||||
expect(registryIncludeCommand.props()).toMatchObject({
|
||||
instruction: composerPackageIncludeStr,
|
||||
instruction: 'composer req @gitlab-org/package-15:1.0.0',
|
||||
copyText: 'Copy require package include',
|
||||
trackingAction: TrackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -108,7 +96,7 @@ describe('ComposerInstallation', () => {
|
|||
'For more information on Composer packages in GitLab, see the documentation.',
|
||||
);
|
||||
expect(findHelpLink().attributes()).toMatchObject({
|
||||
href: composerHelpPath,
|
||||
href: 'composerHelpPath',
|
||||
target: '_blank',
|
||||
});
|
||||
});
|
||||
|
@ -116,15 +104,13 @@ describe('ComposerInstallation', () => {
|
|||
|
||||
describe('root node', () => {
|
||||
it('is normally rendered', () => {
|
||||
createStore();
|
||||
createComponent();
|
||||
|
||||
expect(findRootNode().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('is not rendered when the group does not exist', () => {
|
||||
createStore(false);
|
||||
createComponent();
|
||||
createComponent('');
|
||||
|
||||
expect(findRootNode().exists()).toBe(false);
|
||||
});
|
||||
|
|
|
@ -1,38 +1,27 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as conanPath } from 'jest/packages/details/mock_data';
|
||||
import { conanPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { packageData } from 'jest/packages_and_registries/package_registry/mock_data';
|
||||
import ConanInstallation from '~/packages_and_registries/package_registry/components/details/conan_installation.vue';
|
||||
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
|
||||
import { PACKAGE_TYPE_CONAN } from '~/packages_and_registries/package_registry/constants';
|
||||
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
const packageEntity = { ...packageData(), packageType: PACKAGE_TYPE_CONAN };
|
||||
|
||||
describe('ConanInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const conanInstallationCommandStr = 'foo/command';
|
||||
const conanSetupCommandStr = 'foo/setup';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
conanPath,
|
||||
},
|
||||
getters: {
|
||||
conanInstallationCommand: () => conanInstallationCommandStr,
|
||||
conanSetupCommand: () => conanSetupCommandStr,
|
||||
},
|
||||
});
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
|
||||
const findCodeInstructions = () => wrapper.findAllComponents(CodeInstructions);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent() {
|
||||
wrapper = shallowMount(ConanInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
wrapper = shallowMountExtended(ConanInstallation, {
|
||||
provide: {
|
||||
conanHelpPath: 'conanHelpPath',
|
||||
conanPath: 'conanPath',
|
||||
},
|
||||
propsData: {
|
||||
packageEntity,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -60,13 +49,17 @@ describe('ConanInstallation', () => {
|
|||
|
||||
describe('installation commands', () => {
|
||||
it('renders the correct command', () => {
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(conanInstallationCommandStr);
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(
|
||||
'conan install @gitlab-org/package-15 --remote=gitlab',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct command', () => {
|
||||
expect(findCodeInstructions().at(1).props('instruction')).toBe(conanSetupCommandStr);
|
||||
expect(findCodeInstructions().at(1).props('instruction')).toBe(
|
||||
'conan remote add gitlab conanPath',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import {
|
||||
conanPackage,
|
||||
mavenPackage,
|
||||
npmPackage,
|
||||
nugetPackage,
|
||||
pypiPackage,
|
||||
composerPackage,
|
||||
terraformModule,
|
||||
} from 'jest/packages/mock_data';
|
||||
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
|
||||
import { packageData } from 'jest/packages_and_registries/package_registry/mock_data';
|
||||
import ComposerInstallation from '~/packages_and_registries/package_registry/components/details/composer_installation.vue';
|
||||
import ConanInstallation from '~/packages_and_registries/package_registry/components/details/conan_installation.vue';
|
||||
import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue';
|
||||
|
@ -17,6 +8,21 @@ import MavenInstallation from '~/packages_and_registries/package_registry/compon
|
|||
import NpmInstallation from '~/packages_and_registries/package_registry/components/details/npm_installation.vue';
|
||||
import NugetInstallation from '~/packages_and_registries/package_registry/components/details/nuget_installation.vue';
|
||||
import PypiInstallation from '~/packages_and_registries/package_registry/components/details/pypi_installation.vue';
|
||||
import {
|
||||
PACKAGE_TYPE_CONAN,
|
||||
PACKAGE_TYPE_MAVEN,
|
||||
PACKAGE_TYPE_NPM,
|
||||
PACKAGE_TYPE_NUGET,
|
||||
PACKAGE_TYPE_PYPI,
|
||||
PACKAGE_TYPE_COMPOSER,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
|
||||
const conanPackage = { ...packageData(), packageType: PACKAGE_TYPE_CONAN };
|
||||
const mavenPackage = { ...packageData(), packageType: PACKAGE_TYPE_MAVEN };
|
||||
const npmPackage = { ...packageData(), packageType: PACKAGE_TYPE_NPM };
|
||||
const nugetPackage = { ...packageData(), packageType: PACKAGE_TYPE_NUGET };
|
||||
const pypiPackage = { ...packageData(), packageType: PACKAGE_TYPE_PYPI };
|
||||
const composerPackage = { ...packageData(), packageType: PACKAGE_TYPE_COMPOSER };
|
||||
|
||||
describe('InstallationCommands', () => {
|
||||
let wrapper;
|
||||
|
@ -33,7 +39,6 @@ describe('InstallationCommands', () => {
|
|||
const nugetInstallation = () => wrapper.find(NugetInstallation);
|
||||
const pypiInstallation = () => wrapper.find(PypiInstallation);
|
||||
const composerInstallation = () => wrapper.find(ComposerInstallation);
|
||||
const terraformInstallation = () => wrapper.findComponent(TerraformInstallation);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
|
@ -48,9 +53,8 @@ describe('InstallationCommands', () => {
|
|||
${nugetPackage} | ${nugetInstallation}
|
||||
${pypiPackage} | ${pypiInstallation}
|
||||
${composerPackage} | ${composerInstallation}
|
||||
${terraformModule} | ${terraformInstallation}
|
||||
`('renders', ({ packageEntity, selector }) => {
|
||||
it(`${packageEntity.package_type} instructions exist`, () => {
|
||||
it(`${packageEntity.packageType} instructions exist`, () => {
|
||||
createComponent({ packageEntity });
|
||||
|
||||
expect(selector()).toExist();
|
||||
|
|
|
@ -1,50 +1,79 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as mavenPath } from 'jest/packages/details/mock_data';
|
||||
import { mavenPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import { TrackingActions } from '~/packages/details/constants';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
||||
import {
|
||||
packageData,
|
||||
mavenMetadata,
|
||||
} from 'jest/packages_and_registries/package_registry/mock_data';
|
||||
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
|
||||
import MavenInstallation from '~/packages_and_registries/package_registry/components/details/maven_installation.vue';
|
||||
import {
|
||||
TRACKING_ACTION_COPY_MAVEN_XML,
|
||||
TRACKING_ACTION_COPY_MAVEN_COMMAND,
|
||||
TRACKING_ACTION_COPY_MAVEN_SETUP,
|
||||
TRACKING_ACTION_COPY_GRADLE_INSTALL_COMMAND,
|
||||
TRACKING_ACTION_COPY_GRADLE_ADD_TO_SOURCE_COMMAND,
|
||||
TRACKING_ACTION_COPY_KOTLIN_INSTALL_COMMAND,
|
||||
TRACKING_ACTION_COPY_KOTLIN_ADD_TO_SOURCE_COMMAND,
|
||||
PACKAGE_TYPE_MAVEN,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('MavenInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const xmlCodeBlock = 'foo/xml';
|
||||
const mavenCommandStr = 'foo/command';
|
||||
const mavenSetupXml = 'foo/setup';
|
||||
const gradleGroovyInstallCommandText = 'foo/gradle/groovy/install';
|
||||
const gradleGroovyAddSourceCommandText = 'foo/gradle/groovy/add/source';
|
||||
const gradleKotlinInstallCommandText = 'foo/gradle/kotlin/install';
|
||||
const gradleKotlinAddSourceCommandText = 'foo/gradle/kotlin/add/source';
|
||||
const packageEntity = {
|
||||
...packageData(),
|
||||
packageType: PACKAGE_TYPE_MAVEN,
|
||||
metadata: mavenMetadata(),
|
||||
};
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
mavenPath,
|
||||
},
|
||||
getters: {
|
||||
mavenInstallationXml: () => xmlCodeBlock,
|
||||
mavenInstallationCommand: () => mavenCommandStr,
|
||||
mavenSetupXml: () => mavenSetupXml,
|
||||
gradleGroovyInstalCommand: () => gradleGroovyInstallCommandText,
|
||||
gradleGroovyAddSourceCommand: () => gradleGroovyAddSourceCommandText,
|
||||
gradleKotlinInstalCommand: () => gradleKotlinInstallCommandText,
|
||||
gradleKotlinAddSourceCommand: () => gradleKotlinAddSourceCommandText,
|
||||
},
|
||||
});
|
||||
const mavenHelpPath = 'mavenHelpPath';
|
||||
const mavenPath = 'mavenPath';
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
|
||||
const xmlCodeBlock = `<dependency>
|
||||
<groupId>appGroup</groupId>
|
||||
<artifactId>appName</artifactId>
|
||||
<version>appVersion</version>
|
||||
</dependency>`;
|
||||
const mavenCommandStr = 'mvn dependency:get -Dartifact=appGroup:appName:appVersion';
|
||||
const mavenSetupXml = `<repositories>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>${mavenPath}</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>${mavenPath}</url>
|
||||
</repository>
|
||||
|
||||
<snapshotRepository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>${mavenPath}</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>`;
|
||||
const gradleGroovyInstallCommandText = `implementation 'appGroup:appName:appVersion'`;
|
||||
const gradleGroovyAddSourceCommandText = `maven {
|
||||
url '${mavenPath}'
|
||||
}`;
|
||||
const gradleKotlinInstallCommandText = `implementation("appGroup:appName:appVersion")`;
|
||||
const gradleKotlinAddSourceCommandText = `maven("${mavenPath}")`;
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAllComponents(CodeInstructions);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent({ data = {} } = {}) {
|
||||
wrapper = shallowMount(MavenInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
wrapper = shallowMountExtended(MavenInstallation, {
|
||||
provide: {
|
||||
mavenHelpPath,
|
||||
mavenPath,
|
||||
},
|
||||
propsData: {
|
||||
packageEntity,
|
||||
},
|
||||
data() {
|
||||
return data;
|
||||
},
|
||||
|
@ -98,7 +127,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: xmlCodeBlock,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_MAVEN_XML,
|
||||
trackingAction: TRACKING_ACTION_COPY_MAVEN_XML,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -106,7 +135,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: mavenCommandStr,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_MAVEN_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_MAVEN_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -116,7 +145,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(2).props()).toMatchObject({
|
||||
instruction: mavenSetupXml,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_MAVEN_SETUP,
|
||||
trackingAction: TRACKING_ACTION_COPY_MAVEN_SETUP,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -136,7 +165,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: gradleGroovyInstallCommandText,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_GRADLE_INSTALL_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_GRADLE_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -146,7 +175,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: gradleGroovyAddSourceCommandText,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_GRADLE_ADD_TO_SOURCE_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_GRADLE_ADD_TO_SOURCE_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -166,7 +195,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: gradleKotlinInstallCommandText,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_KOTLIN_INSTALL_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_KOTLIN_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -176,7 +205,7 @@ describe('MavenInstallation', () => {
|
|||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: gradleKotlinAddSourceCommandText,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_KOTLIN_ADD_TO_SOURCE_COMMAND,
|
||||
trackingAction: TRACKING_ACTION_COPY_KOTLIN_ADD_TO_SOURCE_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,6 +18,8 @@ import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.
|
|||
import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
|
||||
import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
|
||||
import * as parsingUtils from '~/pipelines/components/parsing_utils';
|
||||
import getPipelineHeaderData from '~/pipelines/graphql/queries/get_pipeline_header_data.query.graphql';
|
||||
import { mockRunningPipelineHeaderData } from '../mock_data';
|
||||
import { mapCallouts, mockCalloutsResponse, mockPipelineResponse } from './mock_data';
|
||||
|
||||
const defaultProvide = {
|
||||
|
@ -72,8 +74,10 @@ describe('Pipeline graph wrapper', () => {
|
|||
} = {}) => {
|
||||
const callouts = mapCallouts(calloutsList);
|
||||
const getUserCalloutsHandler = jest.fn().mockResolvedValue(mockCalloutsResponse(callouts));
|
||||
const getPipelineHeaderDataHandler = jest.fn().mockResolvedValue(mockRunningPipelineHeaderData);
|
||||
|
||||
const requestHandlers = [
|
||||
[getPipelineHeaderData, getPipelineHeaderDataHandler],
|
||||
[getPipelineDetails, getPipelineDetailsHandler],
|
||||
[getUserCallouts, getUserCalloutsHandler],
|
||||
];
|
||||
|
@ -111,6 +115,11 @@ describe('Pipeline graph wrapper', () => {
|
|||
createComponentWithApollo();
|
||||
expect(getGraph().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('skips querying headerPipeline', () => {
|
||||
createComponentWithApollo();
|
||||
expect(wrapper.vm.$apollo.queries.headerPipeline.skip).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when data has loaded', () => {
|
||||
|
@ -190,12 +199,15 @@ describe('Pipeline graph wrapper', () => {
|
|||
describe('when refresh action is emitted', () => {
|
||||
beforeEach(async () => {
|
||||
createComponentWithApollo();
|
||||
jest.spyOn(wrapper.vm.$apollo.queries.headerPipeline, 'refetch');
|
||||
jest.spyOn(wrapper.vm.$apollo.queries.pipeline, 'refetch');
|
||||
await wrapper.vm.$nextTick();
|
||||
getGraph().vm.$emit('refreshPipelineGraph');
|
||||
});
|
||||
|
||||
it('calls refetch', () => {
|
||||
expect(wrapper.vm.$apollo.queries.headerPipeline.skip).toBe(false);
|
||||
expect(wrapper.vm.$apollo.queries.headerPipeline.refetch).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.pipeline.refetch).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -99,24 +99,6 @@ describe('Pipeline details header', () => {
|
|||
);
|
||||
});
|
||||
|
||||
describe('polling', () => {
|
||||
it('is stopped when pipeline is finished', async () => {
|
||||
wrapper = createComponent({ ...mockRunningPipelineHeader });
|
||||
|
||||
await wrapper.setData({
|
||||
pipeline: { ...mockCancelledPipelineHeader },
|
||||
});
|
||||
|
||||
expect(wrapper.vm.$apollo.queries.pipeline.stopPolling).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('is not stopped when pipeline is not finished', () => {
|
||||
wrapper = createComponent();
|
||||
|
||||
expect(wrapper.vm.$apollo.queries.pipeline.stopPolling).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
describe('Retry action', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -127,6 +127,28 @@ export const mockSuccessfulPipelineHeader = {
|
|||
},
|
||||
};
|
||||
|
||||
export const mockRunningPipelineHeaderData = {
|
||||
data: {
|
||||
project: {
|
||||
pipeline: {
|
||||
...mockRunningPipelineHeader,
|
||||
iid: '28',
|
||||
user: {
|
||||
name: 'Foo',
|
||||
username: 'foobar',
|
||||
webPath: '/foo',
|
||||
email: 'foo@bar.com',
|
||||
avatarUrl: 'link',
|
||||
status: null,
|
||||
__typename: 'UserCore',
|
||||
},
|
||||
__typename: 'Pipeline',
|
||||
},
|
||||
__typename: 'Project',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const stageReply = {
|
||||
name: 'deploy',
|
||||
title: 'deploy: running',
|
||||
|
|
102
spec/graphql/resolvers/paginated_tree_resolver_spec.rb
Normal file
102
spec/graphql/resolvers/paginated_tree_resolver_spec.rb
Normal file
|
@ -0,0 +1,102 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Resolvers::PaginatedTreeResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:repository) { project.repository }
|
||||
|
||||
specify do
|
||||
expect(described_class).to have_nullable_graphql_type(Types::Tree::TreeType.connection_type)
|
||||
end
|
||||
|
||||
describe '#resolve', :aggregate_failures do
|
||||
subject { resolve_repository(args, opts) }
|
||||
|
||||
let(:args) { { ref: 'master' } }
|
||||
let(:opts) { {} }
|
||||
|
||||
let(:start_cursor) { subject.start_cursor }
|
||||
let(:end_cursor) { subject.end_cursor }
|
||||
let(:items) { subject.items }
|
||||
let(:entries) { items.first.entries }
|
||||
|
||||
it 'resolves to a collection with a tree object' do
|
||||
expect(items.first).to be_an_instance_of(Tree)
|
||||
|
||||
expect(start_cursor).to be_nil
|
||||
expect(end_cursor).to be_blank
|
||||
expect(entries.count).to eq(repository.tree.entries.count)
|
||||
end
|
||||
|
||||
context 'with recursive option' do
|
||||
let(:args) { super().merge(recursive: true) }
|
||||
|
||||
it 'resolve to a recursive tree' do
|
||||
expect(entries[4].path).to eq('files/html')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with limited max_page_size' do
|
||||
let(:opts) { { max_page_size: 5 } }
|
||||
|
||||
it 'resolves to a pagination collection with a tree object' do
|
||||
expect(items.first).to be_an_instance_of(Tree)
|
||||
|
||||
expect(start_cursor).to be_nil
|
||||
expect(end_cursor).to be_present
|
||||
expect(entries.count).to eq(5)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when repository does not exist' do
|
||||
before do
|
||||
allow(repository).to receive(:exists?).and_return(false)
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
is_expected.to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Cursor pagination' do
|
||||
context 'when cursor is invalid' do
|
||||
let(:args) { super().merge(after: 'invalid') }
|
||||
|
||||
it { expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) }
|
||||
end
|
||||
|
||||
it 'returns all tree entries during cursor pagination' do
|
||||
cursor = nil
|
||||
|
||||
expected_entries = repository.tree.entries.map(&:path)
|
||||
collected_entries = []
|
||||
|
||||
loop do
|
||||
result = resolve_repository(args.merge(after: cursor), max_page_size: 10)
|
||||
|
||||
collected_entries += result.items.first.entries.map(&:path)
|
||||
|
||||
expect(result.start_cursor).to eq(cursor)
|
||||
cursor = result.end_cursor
|
||||
|
||||
break if cursor.blank?
|
||||
end
|
||||
|
||||
expect(collected_entries).to match_array(expected_entries)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_repository(args, opts = {})
|
||||
field_options = described_class.field_options.merge(
|
||||
owner: resolver_parent,
|
||||
name: 'field_value'
|
||||
).merge(opts)
|
||||
|
||||
field = ::Types::BaseField.new(**field_options)
|
||||
resolve_field(field, repository, args: args, object_type: resolver_parent)
|
||||
end
|
||||
end
|
|
@ -11,6 +11,8 @@ RSpec.describe GitlabSchema.types['Repository'] do
|
|||
|
||||
specify { expect(described_class).to have_graphql_field(:tree) }
|
||||
|
||||
specify { expect(described_class).to have_graphql_field(:paginated_tree, calls_gitaly?: true, max_page_size: 100) }
|
||||
|
||||
specify { expect(described_class).to have_graphql_field(:exists, calls_gitaly?: true, complexity: 2) }
|
||||
|
||||
specify { expect(described_class).to have_graphql_field(:blobs) }
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Database::SchemaMigrations::Context do
|
||||
let(:connection) { ActiveRecord::Base.connection }
|
||||
let(:connection_class) { ActiveRecord::Base }
|
||||
let(:connection) { connection_class.connection }
|
||||
|
||||
let(:context) { described_class.new(connection) }
|
||||
|
||||
|
@ -12,13 +13,65 @@ RSpec.describe Gitlab::Database::SchemaMigrations::Context do
|
|||
expect(context.schema_directory).to eq(File.join(Rails.root, 'db/schema_migrations'))
|
||||
end
|
||||
|
||||
context 'multiple databases' do
|
||||
let(:connection) { Ci::CiDatabaseRecord.connection }
|
||||
context 'CI database' do
|
||||
let(:connection_class) { Ci::CiDatabaseRecord }
|
||||
|
||||
it 'returns a directory path that is database specific' do
|
||||
skip_if_multiple_databases_not_setup
|
||||
|
||||
expect(context.schema_directory).to eq(File.join(Rails.root, 'db/ci_schema_migrations'))
|
||||
expect(context.schema_directory).to eq(File.join(Rails.root, 'db/schema_migrations'))
|
||||
end
|
||||
end
|
||||
|
||||
context 'multiple databases' do
|
||||
let(:connection_class) do
|
||||
Class.new(::ApplicationRecord) do
|
||||
self.abstract_class = true
|
||||
|
||||
def self.name
|
||||
'Gitlab::Database::SchemaMigrations::Context::TestConnection'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:configuration_overrides) { {} }
|
||||
|
||||
before do
|
||||
connection_class.establish_connection(
|
||||
ActiveRecord::Base
|
||||
.connection_pool
|
||||
.db_config
|
||||
.configuration_hash
|
||||
.merge(configuration_overrides)
|
||||
)
|
||||
end
|
||||
|
||||
after do
|
||||
connection_class.remove_connection
|
||||
end
|
||||
|
||||
context 'when `schema_migrations_path` is configured as string' do
|
||||
let(:configuration_overrides) do
|
||||
{ "schema_migrations_path" => "db/ci_schema_migrations" }
|
||||
end
|
||||
|
||||
it 'returns a configured directory path that' do
|
||||
skip_if_multiple_databases_not_setup
|
||||
|
||||
expect(context.schema_directory).to eq(File.join(Rails.root, 'db/ci_schema_migrations'))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when `schema_migrations_path` is configured as symbol' do
|
||||
let(:configuration_overrides) do
|
||||
{ schema_migrations_path: "db/ci_schema_migrations" }
|
||||
end
|
||||
|
||||
it 'returns a configured directory path that' do
|
||||
skip_if_multiple_databases_not_setup
|
||||
|
||||
expect(context.schema_directory).to eq(File.join(Rails.root, 'db/ci_schema_migrations'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!('update_issuable_slas_where_issue_closed')
|
||||
|
||||
RSpec.describe UpdateIssuableSlasWhereIssueClosed, :migration do
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
let(:projects) { table(:projects) }
|
||||
let(:issues) { table(:issues) }
|
||||
let(:issuable_slas) { table(:issuable_slas) }
|
||||
let(:issue_params) { { title: 'title', project_id: project.id } }
|
||||
let(:issue_closed_state) { 2 }
|
||||
|
||||
let!(:namespace) { namespaces.create!(name: 'foo', path: 'foo') }
|
||||
let!(:project) { projects.create!(namespace_id: namespace.id) }
|
||||
let!(:issue_open) { issues.create!(issue_params) }
|
||||
let!(:issue_closed) { issues.create!(issue_params.merge(state_id: issue_closed_state)) }
|
||||
|
||||
let!(:issuable_sla_open_issue) { issuable_slas.create!(issue_id: issue_open.id, due_at: Time.now) }
|
||||
let!(:issuable_sla_closed_issue) { issuable_slas.create!(issue_id: issue_closed.id, due_at: Time.now) }
|
||||
|
||||
it 'sets the issuable_closed attribute to false' do
|
||||
expect(issuable_sla_open_issue.issuable_closed).to eq(false)
|
||||
expect(issuable_sla_closed_issue.issuable_closed).to eq(false)
|
||||
|
||||
migrate!
|
||||
|
||||
expect(issuable_sla_open_issue.reload.issuable_closed).to eq(false)
|
||||
expect(issuable_sla_closed_issue.reload.issuable_closed).to eq(true)
|
||||
end
|
||||
end
|
38
spec/migrations/confirm_security_bot_spec.rb
Normal file
38
spec/migrations/confirm_security_bot_spec.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe ConfirmSecurityBot, :migration do
|
||||
let(:users) { table(:users) }
|
||||
|
||||
let(:user_type) { 8 }
|
||||
|
||||
context 'when bot is not created' do
|
||||
it 'skips migration' do
|
||||
migrate!
|
||||
|
||||
bot = users.find_by(user_type: user_type)
|
||||
|
||||
expect(bot).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when bot is confirmed' do
|
||||
let(:bot) { table(:users).create!(user_type: user_type, confirmed_at: Time.current, projects_limit: 1) }
|
||||
|
||||
it 'skips migration' do
|
||||
expect { migrate! }.not_to change { bot.reload.confirmed_at }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when bot is not confirmed' do
|
||||
let(:bot) { table(:users).create!(user_type: user_type, projects_limit: 1) }
|
||||
|
||||
it 'update confirmed_at' do
|
||||
freeze_time do
|
||||
expect { migrate! }.to change { bot.reload.confirmed_at }.from(nil).to(Time.current)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -83,4 +83,26 @@ RSpec.describe 'getting a repository in a project' do
|
|||
expect(graphql_data['project']['repository']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when paginated tree requested' do
|
||||
let(:fields) do
|
||||
%(
|
||||
paginatedTree {
|
||||
nodes {
|
||||
trees {
|
||||
nodes {
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns paginated tree' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']['repository']['paginatedTree']).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -222,7 +222,7 @@ RSpec.describe Issues::CloseService do
|
|||
|
||||
it 'verifies the number of queries' do
|
||||
recorded = ActiveRecord::QueryRecorder.new { close_issue }
|
||||
expected_queries = 24
|
||||
expected_queries = 25
|
||||
|
||||
expect(recorded.count).to be <= expected_queries
|
||||
expect(recorded.cached_count).to eq(0)
|
||||
|
|
|
@ -898,10 +898,10 @@
|
|||
stylelint-declaration-strict-value "1.7.7"
|
||||
stylelint-scss "3.18.0"
|
||||
|
||||
"@gitlab/svgs@1.208.0":
|
||||
version "1.208.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.208.0.tgz#e298b4d38ac38b7186000cc21bafebebe0766a83"
|
||||
integrity sha512-dK2fXLCPOg0bchIqiNpVPY8RmEIpmR9wo/BHeLpf8NTcEjtAok87hJ+cwySbDvKeu10bSePsgl8NcST61GlNaA==
|
||||
"@gitlab/svgs@1.209.0":
|
||||
version "1.209.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.209.0.tgz#06020b74668df17b9bdaa33b561b4800ca34cc10"
|
||||
integrity sha512-V6NaXDhu899tNCuU4+VepY7Rv2Ge3ViOctrUAS3NQtGcXV1THDhGAg6+OCFpgHr1fhmxYNwpxQ8OTh+HaPvtIA==
|
||||
|
||||
"@gitlab/tributejs@1.0.0":
|
||||
version "1.0.0"
|
||||
|
|
Loading…
Reference in a new issue