Add latest changes from gitlab-org/gitlab@master
|
|
@ -142,7 +142,7 @@ setup-test-env:
|
|||
extends:
|
||||
- .rails-job-base
|
||||
- .setup-test-env-cache
|
||||
- .rails:rules:default-refs-code-backstage-qa
|
||||
- .rails:rules:code-backstage-qa
|
||||
- .use-pg11
|
||||
stage: prepare
|
||||
variables:
|
||||
|
|
@ -244,7 +244,7 @@ update-static-analysis-cache:
|
|||
static-analysis:
|
||||
extends:
|
||||
- .static-analysis-base
|
||||
- .rails:rules:default-refs-code-backstage-qa
|
||||
- .rails:rules:code-backstage-qa
|
||||
stage: test
|
||||
parallel: 4
|
||||
script:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ code_quality:
|
|||
stage: test
|
||||
needs: []
|
||||
variables:
|
||||
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.18"
|
||||
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.23"
|
||||
script:
|
||||
- |
|
||||
if ! docker info &>/dev/null; then
|
||||
|
|
|
|||
|
|
@ -610,10 +610,9 @@
|
|||
- <<: *if-merge-request
|
||||
changes: ["config/**/*"]
|
||||
|
||||
.rails:rules:default-refs-code-backstage-qa:
|
||||
.rails:rules:code-backstage-qa:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-qa-patterns
|
||||
- changes: *code-backstage-qa-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-only-migration:
|
||||
|
|
@ -825,8 +824,7 @@
|
|||
|
||||
.rails:rules:detect-tests:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
- changes: *code-backstage-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:rspec-foss-impact:
|
||||
|
|
@ -1139,8 +1137,7 @@
|
|||
#######################
|
||||
.test-metadata:rules:retrieve-tests-metadata:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
- changes: *code-backstage-patterns
|
||||
when: on_success
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ Graphql/Descriptions:
|
|||
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/267606
|
||||
FactoryBot/InlineAssociation:
|
||||
Exclude:
|
||||
- 'ee/spec/factories/analytics/cycle_analytics/group_stages.rb'
|
||||
- 'ee/spec/factories/geo/event_log.rb'
|
||||
- 'ee/spec/factories/merge_request_blocks.rb'
|
||||
- 'ee/spec/factories/vulnerabilities/feedback.rb'
|
||||
|
|
@ -57,8 +56,6 @@ FactoryBot/InlineAssociation:
|
|||
- 'spec/factories/go_modules.rb'
|
||||
- 'spec/factories/group_group_links.rb'
|
||||
- 'spec/factories/import_export_uploads.rb'
|
||||
- 'spec/factories/uploads.rb'
|
||||
- 'spec/factories/wiki_pages.rb'
|
||||
|
||||
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
|
||||
Rails/SaveBang:
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
mrReviews: {
|
||||
rehydratedMrReviews: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
|
|
@ -164,6 +164,7 @@ export default {
|
|||
'canMerge',
|
||||
'hasConflicts',
|
||||
'viewDiffsFileByFile',
|
||||
'mrReviews',
|
||||
]),
|
||||
...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']),
|
||||
...mapGetters(['isNotesFetched', 'getNoteableData']),
|
||||
|
|
@ -268,7 +269,7 @@ export default {
|
|||
showSuggestPopover: this.showSuggestPopover,
|
||||
viewDiffsFileByFile: fileByFile(this.fileByFileUserPreference),
|
||||
defaultSuggestionCommitMessage: this.defaultSuggestionCommitMessage,
|
||||
mrReviews: this.mrReviews || {},
|
||||
mrReviews: this.rehydratedMrReviews,
|
||||
});
|
||||
|
||||
if (this.shouldShow) {
|
||||
|
|
@ -513,7 +514,7 @@ export default {
|
|||
v-for="(file, index) in diffs"
|
||||
:key="file.newPath"
|
||||
:file="file"
|
||||
:reviewed="fileReviews[index]"
|
||||
:reviewed="fileReviews[file.id]"
|
||||
:is-first-file="index === 0"
|
||||
:is-last-file="index === diffFilesLength - 1"
|
||||
:help-page-path="helpPagePath"
|
||||
|
|
|
|||
|
|
@ -150,6 +150,11 @@ export default {
|
|||
},
|
||||
},
|
||||
watch: {
|
||||
'file.id': {
|
||||
handler: function fileIdHandler() {
|
||||
this.manageViewedEffects();
|
||||
},
|
||||
},
|
||||
'file.file_hash': {
|
||||
handler: function hashChangeWatch(newHash, oldHash) {
|
||||
this.isCollapsed = isCollapsed(this.file);
|
||||
|
|
@ -186,9 +191,7 @@ export default {
|
|||
this.postRender();
|
||||
}
|
||||
|
||||
if (this.reviewed && !this.isCollapsed && this.showLocalFileReviews) {
|
||||
this.handleToggle();
|
||||
}
|
||||
this.manageViewedEffects();
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off(EVT_EXPAND_ALL_FILES, this.expandAllListener);
|
||||
|
|
@ -200,6 +203,11 @@ export default {
|
|||
'setRenderIt',
|
||||
'setFileCollapsedByUser',
|
||||
]),
|
||||
manageViewedEffects() {
|
||||
if (this.reviewed && !this.isCollapsed && this.showLocalFileReviews) {
|
||||
this.handleToggle();
|
||||
}
|
||||
},
|
||||
expandAllListener() {
|
||||
if (this.isCollapsed) {
|
||||
this.handleToggle();
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export default function initDiffsApp(store) {
|
|||
showSuggestPopover: this.showSuggestPopover,
|
||||
fileByFileUserPreference: this.viewDiffsFileByFile,
|
||||
defaultSuggestionCommitMessage: this.defaultSuggestionCommitMessage,
|
||||
mrReviews: getReviewsForMergeRequest(mrPath),
|
||||
rehydratedMrReviews: getReviewsForMergeRequest(mrPath),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ export function isFileReviewed(reviews, file) {
|
|||
}
|
||||
|
||||
export function reviewStatuses(files, reviews) {
|
||||
return files.map((file) => isFileReviewed(reviews, file));
|
||||
return files.reduce((flat, file) => {
|
||||
return {
|
||||
...flat,
|
||||
[file.id]: isFileReviewed(reviews, file),
|
||||
};
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function getReviewsForMergeRequest(mrPath) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { GlButton, GlIcon } from '@gitlab/ui';
|
||||
import { once } from 'lodash';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import { sprintf, s__ } from '~/locale';
|
||||
|
|
@ -26,6 +26,7 @@ export default {
|
|||
IssuesList,
|
||||
Modal,
|
||||
GlButton,
|
||||
GlIcon,
|
||||
},
|
||||
mixins: [Tracking.mixin()],
|
||||
props: {
|
||||
|
|
@ -159,6 +160,18 @@ export default {
|
|||
<template #summary>
|
||||
<div class="gl-display-inline-flex gl-flex-direction-column">
|
||||
<div>{{ reportText(report) }}</div>
|
||||
<div v-if="report.suite_errors">
|
||||
<div v-if="report.suite_errors.head">
|
||||
<gl-icon name="warning" class="gl-mx-2 gl-text-orange-500" />
|
||||
{{ s__('Reports|Head report parsing error:') }}
|
||||
{{ report.suite_errors.head }}
|
||||
</div>
|
||||
<div v-if="report.suite_errors.base">
|
||||
<gl-icon name="warning" class="gl-mx-2 gl-text-orange-500" />
|
||||
{{ s__('Reports|Base report parsing error:') }}
|
||||
{{ report.suite_errors.base }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="hasRecentFailures(report.summary)">
|
||||
{{ recentFailuresText(report.summary) }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
<script>
|
||||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { n__ } from '~/locale';
|
||||
import MrCollapsibleExtension from '../mr_collapsible_extension.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Deployment: () => import('./deployment.vue'),
|
||||
GlSprintf,
|
||||
MrCollapsibleExtension,
|
||||
},
|
||||
props: {
|
||||
deployments: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
deploymentClass: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
hasDeploymentMetrics: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
visualReviewAppMeta: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({
|
||||
sourceProjectId: '',
|
||||
sourceProjectPath: '',
|
||||
mergeRequestId: '',
|
||||
appUrl: '',
|
||||
}),
|
||||
},
|
||||
showVisualReviewAppLink: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
showCollapsedDeployments() {
|
||||
return this.deployments.length > 3;
|
||||
},
|
||||
multipleDeploymentsTitle() {
|
||||
return n__(
|
||||
'Deployments|%{deployments} environment impacted.',
|
||||
'Deployments|%{deployments} environments impacted.',
|
||||
this.deployments.length,
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<mr-collapsible-extension
|
||||
v-if="showCollapsedDeployments"
|
||||
:title="__('View all environments.')"
|
||||
data-testid="mr-collapsed-deployments"
|
||||
>
|
||||
<template #header>
|
||||
<div class="gl-mr-3 gl-line-height-normal">
|
||||
<gl-sprintf :message="multipleDeploymentsTitle">
|
||||
<template #deployments>
|
||||
<span class="gl-font-weight-bold gl-mr-2">{{ deployments.length }}</span>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
<deployment
|
||||
v-for="deployment in deployments"
|
||||
:key="deployment.id"
|
||||
:class="deploymentClass"
|
||||
class="gl-bg-gray-50"
|
||||
:deployment="deployment"
|
||||
:show-metrics="hasDeploymentMetrics"
|
||||
:show-visual-review-app="showVisualReviewAppLink"
|
||||
:visual-review-app-meta="visualReviewAppMeta"
|
||||
/>
|
||||
</mr-collapsible-extension>
|
||||
<div v-else class="mr-widget-extension">
|
||||
<deployment
|
||||
v-for="deployment in deployments"
|
||||
:key="deployment.id"
|
||||
:class="deploymentClass"
|
||||
:deployment="deployment"
|
||||
:show-metrics="hasDeploymentMetrics"
|
||||
:show-visual-review-app="showVisualReviewAppLink"
|
||||
:visual-review-app-meta="visualReviewAppMeta"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
<script>
|
||||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { isNumber } from 'lodash';
|
||||
import { sanitize } from '~/lib/dompurify';
|
||||
import { n__ } from '~/locale';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import MergeRequestStore from '../stores/mr_widget_store';
|
||||
import ArtifactsApp from './artifacts_list_app.vue';
|
||||
import MrCollapsibleExtension from './mr_collapsible_extension.vue';
|
||||
import DeploymentList from './deployment/deployment_list.vue';
|
||||
import MrWidgetContainer from './mr_widget_container.vue';
|
||||
import MrWidgetPipeline from './mr_widget_pipeline.vue';
|
||||
|
||||
|
|
@ -22,9 +21,7 @@ export default {
|
|||
name: 'MrWidgetPipelineContainer',
|
||||
components: {
|
||||
ArtifactsApp,
|
||||
Deployment: () => import('./deployment/deployment.vue'),
|
||||
GlSprintf,
|
||||
MrCollapsibleExtension,
|
||||
DeploymentList,
|
||||
MrWidgetContainer,
|
||||
MrWidgetPipeline,
|
||||
MergeTrainPositionIndicator: () =>
|
||||
|
|
@ -70,7 +67,9 @@ export default {
|
|||
return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
|
||||
},
|
||||
showVisualReviewAppLink() {
|
||||
return this.mr.visualReviewAppAvailable && this.glFeatures.anonymousVisualReviewFeedback;
|
||||
return Boolean(
|
||||
this.mr.visualReviewAppAvailable && this.glFeatures.anonymousVisualReviewFeedback,
|
||||
);
|
||||
},
|
||||
showMergeTrainPositionIndicator() {
|
||||
return isNumber(this.mr.mergeTrainIndex);
|
||||
|
|
@ -116,44 +115,14 @@ export default {
|
|||
<div v-if="mr.exposedArtifactsPath" class="js-exposed-artifacts">
|
||||
<artifacts-app :endpoint="mr.exposedArtifactsPath" />
|
||||
</div>
|
||||
<template v-if="deployments.length">
|
||||
<mr-collapsible-extension
|
||||
v-if="showCollapsedDeployments"
|
||||
:title="__('View all environments.')"
|
||||
data-testid="mr-collapsed-deployments"
|
||||
>
|
||||
<template #header>
|
||||
<div class="gl-mr-3 gl-line-height-normal">
|
||||
<gl-sprintf :message="multipleDeploymentsTitle">
|
||||
<template #deployments>
|
||||
<span class="gl-font-weight-bold gl-mr-2">{{ deployments.length }}</span>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
<deployment
|
||||
v-for="deployment in deployments"
|
||||
:key="deployment.id"
|
||||
:class="deploymentClass"
|
||||
class="gl-bg-gray-50"
|
||||
:deployment="deployment"
|
||||
:show-metrics="hasDeploymentMetrics"
|
||||
:show-visual-review-app="showVisualReviewAppLink"
|
||||
:visual-review-app-meta="visualReviewAppMeta"
|
||||
/>
|
||||
</mr-collapsible-extension>
|
||||
<div v-else class="mr-widget-extension">
|
||||
<deployment
|
||||
v-for="deployment in deployments"
|
||||
:key="deployment.id"
|
||||
:class="deploymentClass"
|
||||
:deployment="deployment"
|
||||
:show-metrics="hasDeploymentMetrics"
|
||||
:show-visual-review-app="showVisualReviewAppLink"
|
||||
:visual-review-app-meta="visualReviewAppMeta"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<deployment-list
|
||||
v-if="deployments.length"
|
||||
:deployments="deployments"
|
||||
:deployment-class="deploymentClass"
|
||||
:has-deployment-metrics="hasDeploymentMetrics"
|
||||
:visual-review-app-meta="visualReviewAppMeta"
|
||||
:show-visual-review-app-link="showVisualReviewAppLink"
|
||||
/>
|
||||
<merge-train-position-indicator
|
||||
v-if="showMergeTrainPositionIndicator"
|
||||
class="mr-widget-extension"
|
||||
|
|
|
|||
|
|
@ -455,8 +455,8 @@ export default {
|
|||
<div class="mr-widget-body media" :class="{ 'gl-pb-3': shouldRenderMergeTrainHelperText }">
|
||||
<status-icon :status="iconClass" />
|
||||
<div class="media-body">
|
||||
<div class="mr-widget-body-controls media space-children">
|
||||
<gl-button-group>
|
||||
<div class="mr-widget-body-controls gl-display-flex gl-align-items-center">
|
||||
<gl-button-group class="gl-align-self-start">
|
||||
<gl-button
|
||||
size="medium"
|
||||
category="primary"
|
||||
|
|
@ -495,46 +495,48 @@ export default {
|
|||
/>
|
||||
</gl-dropdown>
|
||||
</gl-button-group>
|
||||
<div class="media-body-wrap space-children">
|
||||
<template v-if="shouldShowMergeControls">
|
||||
<gl-form-checkbox
|
||||
v-if="canRemoveSourceBranch"
|
||||
id="remove-source-branch-input"
|
||||
v-model="removeSourceBranch"
|
||||
:disabled="isRemoveSourceBranchButtonDisabled"
|
||||
class="js-remove-source-branch-checkbox gl-min-h-7 gl-display-flex gl-align-items-center gl-mr-2"
|
||||
>
|
||||
{{ __('Delete source branch') }}
|
||||
</gl-form-checkbox>
|
||||
<div
|
||||
v-if="shouldShowMergeControls"
|
||||
class="gl-display-flex gl-align-items-center gl-flex-wrap"
|
||||
>
|
||||
<gl-form-checkbox
|
||||
v-if="canRemoveSourceBranch"
|
||||
id="remove-source-branch-input"
|
||||
v-model="removeSourceBranch"
|
||||
:disabled="isRemoveSourceBranchButtonDisabled"
|
||||
class="js-remove-source-branch-checkbox gl-mx-3 gl-display-flex gl-align-items-center"
|
||||
>
|
||||
{{ __('Delete source branch') }}
|
||||
</gl-form-checkbox>
|
||||
|
||||
<!-- Placeholder for EE extension of this component -->
|
||||
<squash-before-merge
|
||||
v-if="shouldShowSquashBeforeMerge"
|
||||
v-model="squashBeforeMerge"
|
||||
:help-path="mr.squashBeforeMergeHelpPath"
|
||||
:is-disabled="isSquashReadOnly"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="bold js-resolve-mr-widget-items-message">
|
||||
<div
|
||||
v-if="hasPipelineMustSucceedConflict"
|
||||
class="gl-display-flex gl-align-items-center"
|
||||
data-testid="pipeline-succeed-conflict"
|
||||
>
|
||||
<gl-sprintf :message="pipelineMustSucceedConflictText" />
|
||||
<gl-link
|
||||
:href="mr.pipelineMustSucceedDocsPath"
|
||||
target="_blank"
|
||||
class="gl-display-flex gl-ml-2"
|
||||
>
|
||||
<gl-icon name="question" />
|
||||
</gl-link>
|
||||
</div>
|
||||
<gl-sprintf v-else :message="mergeDisabledText" />
|
||||
</div>
|
||||
</template>
|
||||
<!-- Placeholder for EE extension of this component -->
|
||||
<squash-before-merge
|
||||
v-if="shouldShowSquashBeforeMerge"
|
||||
v-model="squashBeforeMerge"
|
||||
:help-path="mr.squashBeforeMergeHelpPath"
|
||||
:is-disabled="isSquashReadOnly"
|
||||
class="gl-mx-3"
|
||||
/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="bold js-resolve-mr-widget-items-message gl-ml-3">
|
||||
<div
|
||||
v-if="hasPipelineMustSucceedConflict"
|
||||
class="gl-display-flex gl-align-items-center"
|
||||
data-testid="pipeline-succeed-conflict"
|
||||
>
|
||||
<gl-sprintf :message="pipelineMustSucceedConflictText" />
|
||||
<gl-link
|
||||
:href="mr.pipelineMustSucceedDocsPath"
|
||||
target="_blank"
|
||||
class="gl-display-flex gl-ml-2"
|
||||
>
|
||||
<gl-icon name="question" />
|
||||
</gl-link>
|
||||
</div>
|
||||
<gl-sprintf v-else :message="mergeDisabledText" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="isSHAMismatch" class="d-flex align-items-center mt-2 js-sha-mismatch">
|
||||
<gl-icon name="warning-solid" class="text-warning mr-1" />
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export default {
|
|||
:checked="value"
|
||||
:disabled="isDisabled"
|
||||
name="squash"
|
||||
class="qa-squash-checkbox js-squash-checkbox gl-min-h-7 gl-display-flex gl-align-items-center gl-mr-2"
|
||||
class="qa-squash-checkbox js-squash-checkbox gl-mr-2 gl-display-flex gl-align-items-center"
|
||||
:title="tooltipTitle"
|
||||
@change="(checked) => $emit('input', checked)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Sidekiq system check for cluster mode
|
||||
merge_request: 55530
|
||||
author: Horst Prote
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Reschedule artifact expiry backfill
|
||||
merge_request: 55093
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Display parsing errors in test reports MR widget
|
||||
merge_request: 55037
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix 'viewed' checkbox in single-file view mode
|
||||
merge_request: 55922
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RescheduleArtifactExpiryBackfill < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
MIGRATION = 'BackfillArtifactExpiryDate'.freeze
|
||||
SWITCH_DATE = Date.new(2020, 06, 22).freeze
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
class JobArtifact < ActiveRecord::Base
|
||||
include EachBatch
|
||||
|
||||
self.inheritance_column = :_type_disabled
|
||||
self.table_name = 'ci_job_artifacts'
|
||||
|
||||
scope :without_expiry_date, -> { where(expire_at: nil) }
|
||||
scope :before_switch, -> { where("date(created_at AT TIME ZONE 'UTC') < ?::date", SWITCH_DATE) }
|
||||
end
|
||||
|
||||
def up
|
||||
Gitlab::BackgroundMigration.steal(MIGRATION) do |job|
|
||||
job.delete
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
queue_background_migration_jobs_by_range_at_intervals(
|
||||
JobArtifact.without_expiry_date.before_switch,
|
||||
MIGRATION,
|
||||
2.minutes,
|
||||
batch_size: 200_000
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
Gitlab::BackgroundMigration.steal(MIGRATION) do |job|
|
||||
job.delete
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
cc9f56a872cf5e9084e863adc599545754594fb03f30f18433923e0429986e39
|
||||
|
Before Width: | Height: | Size: 26 KiB |
|
|
@ -176,7 +176,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
|
|||
- [Job logs](job_logs.md): Information about the job logs.
|
||||
- [Register runners](../ci/runners/README.md#types-of-runners): Learn how to register and configure runners.
|
||||
- [Shared runners pipelines quota](../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota): Limit the usage of pipeline minutes for shared runners.
|
||||
- [Enable/disable Auto DevOps](../topics/autodevops/index.md#enablingdisabling-auto-devops): Enable or disable Auto DevOps for your instance.
|
||||
- [Enable/disable Auto DevOps](../topics/autodevops/index.md#enable-or-disable-auto-devops): Enable or disable Auto DevOps for your instance.
|
||||
|
||||
## Snippet settings
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,33 @@ These locations can be configured using the options described below.
|
|||
|
||||
Use [external object storage](https://docs.gitlab.com/charts/advanced/external-object-storage/#lfs-artifacts-uploads-packages-external-diffs-pseudonymizer-terraform-state-dependency-proxy) configuration for [GitLab Helm chart](https://docs.gitlab.com/charts/) installations.
|
||||
|
||||
## Disabling Terraform state
|
||||
|
||||
To disable terraform state site-wide, follow the steps below.
|
||||
A GitLab administrator may want to disable Terraform state to reduce diskspace or if Terraform is not used in your instance.
|
||||
To do so, follow the steps below according to your installation's type.
|
||||
|
||||
**In Omnibus installations:**
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['terraform_state_enabled'] = false
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
|
||||
|
||||
**In installations from source:**
|
||||
|
||||
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
|
||||
|
||||
```yaml
|
||||
terraform_state:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
|
||||
|
||||
## Using local storage
|
||||
|
||||
The default configuration uses local storage. To change the location where
|
||||
|
|
|
|||
|
|
@ -210,10 +210,10 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
|
|||
|
||||
## Delete merged branches
|
||||
|
||||
Will delete all branches that are merged into the project's default branch.
|
||||
Deletes all branches that are merged into the project's default branch.
|
||||
|
||||
NOTE:
|
||||
[Protected branches](../user/project/protected_branches.md) will not be deleted as part of this operation.
|
||||
[Protected branches](../user/project/protected_branches.md) are not deleted as part of this operation.
|
||||
|
||||
```plaintext
|
||||
DELETE /projects/:id/repository/merged_branches
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ GET /projects/:id/repository/commits
|
|||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
|
||||
| `ref_name` | string | no | The name of a repository branch, tag or revision range, or if not given the default branch |
|
||||
| `since` | string | no | Only commits after or on this date will be returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ |
|
||||
| `until` | string | no | Only commits before or on this date will be returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ |
|
||||
| `since` | string | no | Only commits after or on this date are returned in ISO 8601 format `YYYY-MM-DDTHH:MM:SSZ` |
|
||||
| `until` | string | no | Only commits before or on this date are returned in ISO 8601 format `YYYY-MM-DDTHH:MM:SSZ` |
|
||||
| `path` | string | no | The file path |
|
||||
| `all` | boolean | no | Retrieve every commit from the repository |
|
||||
| `with_stats` | boolean | no | Stats about each commit will be added to the response |
|
||||
| `with_stats` | boolean | no | Stats about each commit are added to the response |
|
||||
| `first_parent` | boolean | no | Follow only the first parent commit upon seeing a merge commit |
|
||||
| `order` | string | no | List commits in order. Possible values: `default`, [`topo`](https://git-scm.com/docs/git-log#Documentation/git-log.txt---topo-order). Defaults to `default`, the commits are shown in reverse chronological order. |
|
||||
|
||||
|
|
@ -101,9 +101,9 @@ POST /projects/:id/repository/commits
|
|||
| `action` | string | yes | The action to perform, `create`, `delete`, `move`, `update`, `chmod`|
|
||||
| `file_path` | string | yes | Full path to the file. Ex. `lib/class.rb` |
|
||||
| `previous_path` | string | no | Original full path to the file being moved. Ex. `lib/class1.rb`. Only considered for `move` action. |
|
||||
| `content` | string | no | File content, required for all except `delete`, `chmod`, and `move`. Move actions that do not specify `content` will preserve the existing file content, and any other value of `content` will overwrite the file content. |
|
||||
| `content` | string | no | File content, required for all except `delete`, `chmod`, and `move`. Move actions that do not specify `content` preserve the existing file content, and any other value of `content` overwrites the file content. |
|
||||
| `encoding` | string | no | `text` or `base64`. `text` is default. |
|
||||
| `last_commit_id` | string | no | Last known file commit ID. Will be only considered in update, move, and delete actions. |
|
||||
| `last_commit_id` | string | no | Last known file commit ID. Only considered in update, move, and delete actions. |
|
||||
| `execute_filemode` | boolean | no | When `true/false` enables/disables the execute flag on the file. Only considered for `chmod` action. |
|
||||
|
||||
```shell
|
||||
|
|
@ -333,7 +333,7 @@ Example response:
|
|||
}
|
||||
```
|
||||
|
||||
In the event of a failed cherry-pick, the response will provide context about
|
||||
In the event of a failed cherry-pick, the response provides context about
|
||||
why:
|
||||
|
||||
```json
|
||||
|
|
@ -348,9 +348,9 @@ indicates that the commit already exists in the target branch. The other
|
|||
possible error code is `conflict`, which indicates that there was a merge
|
||||
conflict.
|
||||
|
||||
When `dry_run` is enabled, the server will attempt to apply the cherry-pick _but
|
||||
When `dry_run` is enabled, the server attempts to apply the cherry-pick _but
|
||||
not actually commit any resulting changes_. If the cherry-pick applies cleanly,
|
||||
the API will respond with `200 OK`:
|
||||
the API responds with `200 OK`:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -358,7 +358,7 @@ the API will respond with `200 OK`:
|
|||
}
|
||||
```
|
||||
|
||||
In the event of a failure, you'll see an error identical to a failure without
|
||||
In the event of a failure, an error displays that is identical to a failure without
|
||||
dry run.
|
||||
|
||||
## Revert a commit
|
||||
|
|
@ -404,7 +404,7 @@ Example response:
|
|||
}
|
||||
```
|
||||
|
||||
In the event of a failed revert, the response will provide context about why:
|
||||
In the event of a failed revert, the response provides context about why:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -417,9 +417,9 @@ In this case, the revert failed because the attempted revert generated a merge
|
|||
conflict. The other possible error code is `empty`, which indicates that the
|
||||
changeset was empty, likely due to the change having already been reverted.
|
||||
|
||||
When `dry_run` is enabled, the server will attempt to apply the revert _but not
|
||||
When `dry_run` is enabled, the server attempts to apply the revert _but not
|
||||
actually commit any resulting changes_. If the revert applies cleanly, the API
|
||||
will respond with `200 OK`:
|
||||
responds with `200 OK`:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -427,7 +427,7 @@ will respond with `200 OK`:
|
|||
}
|
||||
```
|
||||
|
||||
In the event of a failure, you'll see an error identical to a failure without
|
||||
In the event of a failure, an error displays that is identical to a failure without
|
||||
dry run.
|
||||
|
||||
## Get the diff of a commit
|
||||
|
|
@ -511,7 +511,7 @@ In order to post a comment in a particular line of a particular file, you must
|
|||
specify the full commit SHA, the `path`, the `line` and `line_type` should be
|
||||
`new`.
|
||||
|
||||
The comment will be added at the end of the last commit if at least one of the
|
||||
The comment is added at the end of the last commit if at least one of the
|
||||
cases below is valid:
|
||||
|
||||
- the `sha` is instead a branch or a tag and the `line` or `path` are invalid
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Discussions are a set of related notes on:
|
|||
- Merge requests
|
||||
- Commits
|
||||
|
||||
This includes system notes, which are notes about changes to the object (for example, when a milestone changes, there will be a corresponding system note). Label notes are not part of this API, but recorded as separate events in [resource label events](resource_label_events.md).
|
||||
This includes system notes, which are notes about changes to the object (for example, when a milestone changes, a corresponding system note is added). Label notes are not part of this API, but recorded as separate events in [resource label events](resource_label_events.md).
|
||||
|
||||
## Discussions pagination
|
||||
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ You can update project approval rules using the following endpoint:
|
|||
PUT /projects/:id/approval_rules/:approval_rule_id
|
||||
```
|
||||
|
||||
**Important:** Approvers and groups not in the `users`/`groups` parameters will be **removed**
|
||||
**Important:** Approvers and groups not in the `users`/`groups` parameters are **removed**
|
||||
|
||||
**Parameters:**
|
||||
|
||||
|
|
@ -516,7 +516,7 @@ the following endpoint:
|
|||
PUT /projects/:id/approvers
|
||||
```
|
||||
|
||||
**Important:** Approvers and groups not in the request will be **removed**
|
||||
**Important:** Approvers and groups not in the request are **removed**
|
||||
|
||||
**Parameters:**
|
||||
|
||||
|
|
@ -784,7 +784,7 @@ the following endpoint:
|
|||
PUT /projects/:id/merge_requests/:merge_request_iid/approvers
|
||||
```
|
||||
|
||||
**Important:** Approvers and groups not in the request will be **removed**
|
||||
**Important:** Approvers and groups not in the request are **removed**
|
||||
|
||||
**Parameters:**
|
||||
|
||||
|
|
@ -855,8 +855,8 @@ You can request information about a merge request's approval state by using the
|
|||
GET /projects/:id/merge_requests/:merge_request_iid/approval_state
|
||||
```
|
||||
|
||||
The `approval_rules_overwritten` will be `true` if the merge request level rules
|
||||
are created for the merge request. If there's none, it'll be `false`.
|
||||
The `approval_rules_overwritten` are `true` if the merge request level rules
|
||||
are created for the merge request. If there are none, it is `false`.
|
||||
|
||||
This includes additional information about the users who have already approved
|
||||
(`approved_by`) and whether a rule is already approved (`approved`).
|
||||
|
|
@ -1019,8 +1019,8 @@ POST /projects/:id/merge_requests/:merge_request_iid/approval_rules
|
|||
| `group_ids` | Array | no | The ids of groups as approvers |
|
||||
|
||||
**Important:** When `approval_project_rule_id` is set, the `name`, `users` and
|
||||
`groups` of project-level rule will be copied. The `approvals_required` specified
|
||||
will be used.
|
||||
`groups` of project-level rule are copied. The `approvals_required` specified
|
||||
is used.
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -1091,7 +1091,7 @@ You can update merge request approval rules using the following endpoint:
|
|||
PUT /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id
|
||||
```
|
||||
|
||||
**Important:** Approvers and groups not in the `users`/`groups` parameters will be **removed**
|
||||
**Important:** Approvers and groups not in the `users`/`groups` parameters are **removed**
|
||||
|
||||
**Important:** Updating a `report_approver` or `code_owner` rule is not allowed.
|
||||
These are system generated rules.
|
||||
|
|
@ -1212,7 +1212,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/approve
|
|||
The `sha` parameter works in the same way as
|
||||
when [accepting a merge request](merge_requests.md#accept-mr): if it is passed, then it must
|
||||
match the current HEAD of the merge request for the approval to be added. If it
|
||||
does not match, the response code will be `409`.
|
||||
does not match, the response code is `409`.
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ type: reference, api
|
|||
|
||||
## Placeholder tokens
|
||||
|
||||
Badges support placeholders that will be replaced in real time in both the link and image URL. The allowed placeholders are:
|
||||
Badges support placeholders that are replaced in real time in both the link and image URL. The allowed placeholders are:
|
||||
|
||||
<!-- vale gitlab.Spelling = NO -->
|
||||
|
||||
- **%{project_path}**: will be replaced by the project path.
|
||||
- **%{project_id}**: will be replaced by the project ID.
|
||||
- **%{default_branch}**: will be replaced by the project default branch.
|
||||
- **%{commit_sha}**: will be replaced by the last project's commit SHA.
|
||||
- **%{project_path}**: Replaced by the project path.
|
||||
- **%{project_id}**: Replaced by the project ID.
|
||||
- **%{default_branch}**: Replaced by the project default branch.
|
||||
- **%{commit_sha}**: Replaced by the last project's commit SHA.
|
||||
|
||||
<!-- vale gitlab.Spelling = YES -->
|
||||
## List all badges of a project
|
||||
|
|
@ -162,7 +162,7 @@ Example response:
|
|||
|
||||
## Remove a badge from a project
|
||||
|
||||
Removes a badge from a project. Only project's badges will be removed by using this endpoint.
|
||||
Removes a badge from a project. Only project badges are removed by using this endpoint.
|
||||
|
||||
```plaintext
|
||||
DELETE /projects/:id/badges/:badge_id
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
|
|||
```
|
||||
|
||||
NOTE:
|
||||
The upload request will be sent with `Content-Type: application/gzip` header. Ensure that your pre-signed URL includes this as part of the signature.
|
||||
The upload request is sent with `Content-Type: application/gzip` header. Ensure that your pre-signed URL includes this as part of the signature.
|
||||
|
||||
## Export status
|
||||
|
||||
|
|
@ -138,14 +138,14 @@ POST /projects/import
|
|||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | -------------- | -------- | ---------------------------------------- |
|
||||
| `namespace` | integer/string | no | The ID or path of the namespace that the project will be imported to. Defaults to the current user's namespace |
|
||||
| `namespace` | integer/string | no | The ID or path of the namespace to import the project to. Defaults to the current user's namespace |
|
||||
| `name` | string | no | The name of the project to be imported. Defaults to the path of the project if not provided |
|
||||
| `file` | string | yes | The file to be uploaded |
|
||||
| `path` | string | yes | Name and path for new project |
|
||||
| `overwrite` | boolean | no | If there is a project with the same path the import will overwrite it. Default to false |
|
||||
| `overwrite` | boolean | no | If there is a project with the same path the import overwrites it. Default to false |
|
||||
| `override_params` | Hash | no | Supports all fields defined in the [Project API](projects.md) |
|
||||
|
||||
The override parameters passed will take precedence over all values defined inside the export file.
|
||||
The override parameters passed take precedence over all values defined inside the export file.
|
||||
|
||||
To upload a file from your file system, use the `--form` argument. This causes
|
||||
cURL to post data using the header `Content-Type: multipart/form-data`.
|
||||
|
|
@ -220,7 +220,7 @@ Status can be one of:
|
|||
- `started`
|
||||
- `finished`
|
||||
|
||||
If the status is `failed`, it will include the import error message under `import_error`.
|
||||
If the status is `failed`, it includes the import error message under `import_error`.
|
||||
If the status is `failed`, `started` or `finished`, the `failed_relations` array might
|
||||
be populated with any occurrences of relations that failed to import either due to
|
||||
unrecoverable errors or because retries were exhausted (a typical example are query timeouts.)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ This API is a project-specific version of these endpoints:
|
|||
- [Issue and merge request templates](../user/project/description_templates.md)
|
||||
([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37890) in GitLab 13.3)
|
||||
|
||||
It deprecates these endpoints, which will be removed for API version 5.
|
||||
It deprecates these endpoints, which are scheduled for removal in API version 5.
|
||||
|
||||
In addition to templates common to the entire instance, project-specific
|
||||
templates are also available from this API endpoint.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Every API call to vulnerabilities must be [authenticated](README.md#authenticati
|
|||
|
||||
Vulnerability permissions inherit permissions from their project. If a project is
|
||||
private, and a user isn't a member of the project to which the vulnerability
|
||||
belongs, requests to that project will return a `404 Not Found` status code.
|
||||
belongs, requests to that project returns a `404 Not Found` status code.
|
||||
|
||||
## Vulnerabilities pagination
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ List all of a project's vulnerabilities.
|
|||
|
||||
If an authenticated user does not have permission to
|
||||
[use the Project Security Dashboard](../user/permissions.md#project-members-permissions),
|
||||
`GET` requests for vulnerabilities of this project will result in a `403` status code.
|
||||
`GET` requests for vulnerabilities of this project result in a `403` status code.
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/vulnerabilities
|
||||
|
|
@ -109,7 +109,7 @@ Creates a new vulnerability.
|
|||
|
||||
If an authenticated user does not have a permission to
|
||||
[create a new vulnerability](../user/permissions.md#project-members-permissions),
|
||||
this request will result in a `403` status code.
|
||||
this request results in a `403` status code.
|
||||
|
||||
```plaintext
|
||||
POST /projects/:id/vulnerabilities?finding_id=<your_finding_id>
|
||||
|
|
@ -118,7 +118,7 @@ POST /projects/:id/vulnerabilities?finding_id=<your_finding_id>
|
|||
| Attribute | Type | Required | Description |
|
||||
| ------------------- | ----------------- | ---------- | -----------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) which the authenticated user is a member of |
|
||||
| `finding_id` | integer or string | yes | The ID of a Vulnerability Finding from which the new Vulnerability will be created |
|
||||
| `finding_id` | integer or string | yes | The ID of a Vulnerability Finding to create the new Vulnerability from |
|
||||
|
||||
The other attributes of a newly created Vulnerability are populated from
|
||||
its source Vulnerability Finding, or with these default values:
|
||||
|
|
|
|||
|
|
@ -48,14 +48,14 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
For security reasons, the `url` attribute will always be scrubbed of username
|
||||
For security reasons, the `url` attribute is always scrubbed of username
|
||||
and password information.
|
||||
|
||||
## Create a remote mirror
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24189) in GitLab 12.9.
|
||||
|
||||
Create a remote mirror for a project. The mirror will be disabled by default. You can enable it by including the optional parameter `enabled` when creating it:
|
||||
Create a remote mirror for a project. The mirror is disabled by default. You can enable it by including the optional parameter `enabled` when creating it:
|
||||
|
||||
```plaintext
|
||||
POST /projects/:id/remote_mirrors
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ PUT /projects/:id/repository/submodules/:submodule
|
|||
| `submodule` | string | yes | URL-encoded full path to the submodule. For example, `lib%2Fclass%2Erb` |
|
||||
| `branch` | string | yes | Name of the branch to commit into |
|
||||
| `commit_sha` | string | yes | Full commit SHA to update the submodule to |
|
||||
| `commit_message` | string | no | Commit message. If no message is provided, a default one will be set |
|
||||
| `commit_message` | string | no | Commit message. If no message is provided, a default is set |
|
||||
|
||||
```shell
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/submodules/lib%2Fmodules%2Fexample" \
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ GET /search
|
|||
| `search` | string | yes | The search query |
|
||||
| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
|
||||
| `confidential` | boolean | no | Filter by confidentiality. Issues scope is supported; it is ignored for other scopes. |
|
||||
| `order_by` | string | no | Allowed values are `created_at` only. If this is not set, the results will either be sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `sort` | string | no | Allowed values are `asc` or `desc` only. If this is not set, the results will either be sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `order_by` | string | no | Allowed values are `created_at` only. If this is not set, the results are either sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `sort` | string | no | Allowed values are `asc` or `desc` only. If this is not set, the results are either sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
|
||||
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, snippet_titles, users.
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
|
||||
### Scope: commits **(PREMIUM)**
|
||||
|
||||
|
|
@ -371,7 +371,7 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
|
||||
### Scope: notes **(PREMIUM)**
|
||||
|
||||
|
|
@ -434,7 +434,7 @@ Example response:
|
|||
|
||||
Search within the specified group.
|
||||
|
||||
If a user is not a member of a group and the group is private, a `GET` request on that group will result to a `404` status code.
|
||||
If a user is not a member of a group and the group is private, a `GET` request on that group results in a `404` status code.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/search
|
||||
|
|
@ -447,8 +447,8 @@ GET /groups/:id/search
|
|||
| `search` | string | yes | The search query |
|
||||
| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
|
||||
| `confidential` | boolean | no | Filter by confidentiality. Issues scope is supported; it is ignored for other scopes. |
|
||||
| `order_by` | string | no | Allowed values are `created_at` only. If this is not set, the results will either be sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `sort` | string | no | Allowed values are `asc` or `desc` only. If this is not set, the results will either be sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `order_by` | string | no | Allowed values are `created_at` only. If this is not set, the results are either sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `sort` | string | no | Allowed values are `asc` or `desc` only. If this is not set, the results are either sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
|
||||
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, users.
|
||||
|
||||
|
|
@ -685,7 +685,7 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
|
||||
### Scope: commits **(PREMIUM)**
|
||||
|
||||
|
|
@ -761,7 +761,7 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
|
||||
### Scope: notes **(PREMIUM)**
|
||||
|
||||
|
|
@ -824,7 +824,7 @@ Example response:
|
|||
|
||||
Search within the specified project.
|
||||
|
||||
If a user is not a member of a project and the project is private, a `GET` request on that project will result to a `404` status code.
|
||||
If a user is not a member of a project and the project is private, a `GET` request on that project results in a `404` status code.
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/search
|
||||
|
|
@ -838,8 +838,8 @@ GET /projects/:id/search
|
|||
| `ref` | string | no | The name of a repository branch or tag to search on. The project's default branch is used by default. This is only applicable for scopes: commits, blobs, and wiki_blobs. |
|
||||
| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
|
||||
| `confidential` | boolean | no | Filter by confidentiality. Issues scope is supported; it is ignored for other scopes. |
|
||||
| `order_by` | string | no | Allowed values are `created_at` only. If this is not set, the results will either be sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `sort` | string | no | Allowed values are `asc` or `desc` only. If this is not set, the results will either be sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `order_by` | string | no | Allowed values are `created_at` only. If this is not set, the results are either sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
| `sort` | string | no | Allowed values are `asc` or `desc` only. If this is not set, the results are either sorted by `created_at` in descending order for basic search, or by the most relevant documents when using advanced search.|
|
||||
|
||||
Search the expression within the specified scope. Currently these scopes are supported: issues, merge_requests, milestones, notes, wiki_blobs, commits, blobs, users.
|
||||
|
||||
|
|
@ -1096,7 +1096,7 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` are intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
|
||||
### Scope: commits **(PREMIUM)**
|
||||
|
||||
|
|
@ -1178,7 +1178,7 @@ Example response:
|
|||
```
|
||||
|
||||
NOTE:
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
|
||||
|
||||
### Scope: users
|
||||
|
||||
|
|
|
|||
|
|
@ -160,11 +160,10 @@ Example response:
|
|||
}
|
||||
```
|
||||
|
||||
The message will be `null` when creating a lightweight tag otherwise
|
||||
it will contain the annotation.
|
||||
The message is `null` when creating a lightweight tag. Otherwise, it contains the annotation.
|
||||
|
||||
The target will contain the tag objects ID when creating annotated tags,
|
||||
otherwise it will contain the commit ID when creating lightweight tags.
|
||||
The target contains the tag objects ID when creating annotated tags,
|
||||
otherwise it contains the commit ID when creating lightweight tags.
|
||||
|
||||
In case of an error,
|
||||
status code `405` with an explaining error message is returned.
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
|
@ -86,6 +86,9 @@ Breaking changes are:
|
|||
- Removing or renaming a field, argument, enum value or mutation.
|
||||
- Changing the type of a field, argument or enum value.
|
||||
- Raising the [complexity](#max-complexity) of a field or complexity multipliers in a resolver.
|
||||
- Changing a field from being _not_ nullable (`null: false`) to nullable (`null: true`), as
|
||||
discussed in [Nullable fields](#nullable-fields).
|
||||
- Changing an argument from being optional (`required: false`) to being required (`required: true`).
|
||||
- Changing the [max page size](#page-size-limit) of a connection.
|
||||
- Lowering the global limits for query complexity and depth.
|
||||
- Anything else that can result in queries hitting a limit that previously was allowed.
|
||||
|
|
|
|||
|
|
@ -934,6 +934,10 @@ To add data for aggregated metrics into Usage Ping payload you should add corres
|
|||
- `operator`: Operator that defines how the aggregated metric data is counted. Available operators are:
|
||||
- `OR`: Removes duplicates and counts all entries that triggered any of listed events.
|
||||
- `AND`: Removes duplicates and counts all elements that were observed triggering all of following events.
|
||||
- `time_frame`: One or more valid time frames. Use these to limit the data included in aggregated metric to events within a specific date-range. Valid time frames are:
|
||||
- `7d`: Last seven days of data.
|
||||
- `28d`: Last twenty eight days of data.
|
||||
- `all`: All historical data, only available for `database` sourced aggregated metrics.
|
||||
- `source`: Data source used to collect all events data included in aggregated metric. Valid data sources are:
|
||||
- [`database`](#database-sourced-aggregated-metrics)
|
||||
- [`redis`](#redis-sourced-aggregated-metrics)
|
||||
|
|
@ -949,18 +953,24 @@ To add data for aggregated metrics into Usage Ping payload you should add corres
|
|||
Example aggregated metric entries:
|
||||
|
||||
```yaml
|
||||
- name: product_analytics_test_metrics_union_redis_sourced
|
||||
- name: example_metrics_union
|
||||
operator: OR
|
||||
events: ['i_search_total', 'i_search_advanced', 'i_search_paid']
|
||||
source: redis
|
||||
- name: product_analytics_test_metrics_intersection_with_feautre_flag_database_sourced
|
||||
time_frame:
|
||||
- 7d
|
||||
- 28d
|
||||
- name: example_metrics_intersection
|
||||
operator: AND
|
||||
source: database
|
||||
time_frame:
|
||||
- 28d
|
||||
- all
|
||||
events: ['dependency_scanning_pipeline_all_time', 'container_scanning_pipeline_all_time']
|
||||
feature_flag: example_aggregated_metric
|
||||
```
|
||||
|
||||
Aggregated metrics are added under `aggregated_metrics` key in both `counts_weekly` and `counts_monthly` top level keys in Usage Ping payload.
|
||||
Aggregated metrics collected in `7d` and `28d` time frames are added into Usage Ping payload under the `aggregated_metrics` sub-key in the `counts_weekly` and `counts_monthly` top level keys.
|
||||
|
||||
```ruby
|
||||
{
|
||||
|
|
@ -973,14 +983,35 @@ Aggregated metrics are added under `aggregated_metrics` key in both `counts_week
|
|||
:project_snippets => 407,
|
||||
:promoted_issues => 719,
|
||||
:aggregated_metrics => {
|
||||
:product_analytics_test_metrics_union => 7,
|
||||
:product_analytics_test_metrics_intersection_with_feautre_flag => 2
|
||||
:example_metrics_union => 7,
|
||||
:example_metrics_intersection => 2
|
||||
},
|
||||
:snippets => 2513
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Aggregated metrics for `all` time frame are present in the `count` top level key, with the `aggregate_` prefix added to their name.
|
||||
|
||||
For example:
|
||||
|
||||
`example_metrics_intersection`
|
||||
|
||||
Becomes:
|
||||
|
||||
`counts.aggregate_example_metrics_intersection`
|
||||
|
||||
```ruby
|
||||
{
|
||||
:counts => {
|
||||
:deployments => 11003,
|
||||
:successful_deployments => 178,
|
||||
:failed_deployments => 1275,
|
||||
:aggregate_example_metrics_intersection => 12
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Redis sourced aggregated metrics
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45979) in GitLab 13.6.
|
||||
|
|
@ -992,6 +1023,7 @@ you must fulfill the following requirements:
|
|||
[`known_events/*.yml`](#known-events-are-added-automatically-in-usage-data-payload) files.
|
||||
1. All events listed at `events` attribute must have the same `redis_slot` attribute.
|
||||
1. All events listed at `events` attribute must have the same `aggregation` attribute.
|
||||
1. `time_frame` does not include `all` value, which is unavailable for Redis sourced aggregated metrics.
|
||||
|
||||
### Database sourced aggregated metrics
|
||||
|
||||
|
|
@ -1051,17 +1083,24 @@ end
|
|||
#### Add new aggregated metric definition
|
||||
|
||||
After all metrics are persisted, you can add an aggregated metric definition at
|
||||
[`aggregated_metrics/`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/aggregated_metrics/). When adding definitions for metrics names listed in the
|
||||
`events:` attribute, use the same names you passed in the `metric_name` argument
|
||||
while persisting metrics in previous step.
|
||||
[`aggregated_metrics/`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/aggregated_metrics/).
|
||||
|
||||
To declare the aggregate of metrics collected with [Estimated Batch Counters](#estimated-batch-counters),
|
||||
you must fulfill the following requirements:
|
||||
|
||||
- Metrics names listed in the `events:` attribute, have to use the same names you passed in the `metric_name` argument while persisting metrics in previous step.
|
||||
- Every metric listed in the `events:` attribute, has to be persisted for **every** selected `time_frame:` value.
|
||||
|
||||
Example definition:
|
||||
|
||||
```yaml
|
||||
- name: product_analytics_test_metrics_intersection_database_sourced
|
||||
- name: example_metrics_intersection_database_sourced
|
||||
operator: AND
|
||||
source: database
|
||||
events: ['dependency_scanning_pipeline', 'container_scanning_pipeline']
|
||||
time_frame:
|
||||
- 28d
|
||||
- all
|
||||
```
|
||||
|
||||
## Example Usage Ping payload
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ When you create a new branch (in your [terminal](start-using-git.md#create-a-bra
|
|||
[the web interface](../user/project/repository/web_editor.md#create-a-new-branch)),
|
||||
you are creating a snapshot of a certain branch, usually the main `master` branch,
|
||||
at its current state. From there, you can start to make your own changes without
|
||||
affecting the main codebase. The history of your changes will be tracked in your branch.
|
||||
affecting the main codebase. The history of your changes is tracked in your branch.
|
||||
|
||||
When your changes are ready, you then merge them into the rest of the codebase with a
|
||||
[merge request](../user/project/merge_requests/creating_merge_requests.md).
|
||||
|
|
|
|||
|
|
@ -35,4 +35,4 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/workflow.html'
|
|||
|
||||
1. Create a merge request.
|
||||
|
||||
1. Your team lead will review the code & merge it to the main branch.
|
||||
1. Your team lead reviews the code and merges it to the main branch.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ type: index
|
|||
# GitLab basics guides **(FREE)**
|
||||
|
||||
This section provides resources to help you start working with GitLab and Git by focusing
|
||||
on the basic features that you will need to use.
|
||||
on the basic features that you must use.
|
||||
|
||||
This documentation is split into the following groups:
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ The following are guides to basic GitLab functionality:
|
|||
If you're familiar with Git on the command line, you can interact with your GitLab
|
||||
projects just as you would with any other Git repository.
|
||||
|
||||
These resources will help you get further acclimated to working on the command line.
|
||||
These resources can help you get further acclimated to working on the command line.
|
||||
|
||||
- [Start using Git on the command line](start-using-git.md), for some simple Git commands.
|
||||
- [Command line basics](command-line-commands.md), to create and edit files using the command line.
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ directly in the browser, you’ll eventually need to use Git through the command
|
|||
tasks.
|
||||
|
||||
For example, if you need to fix complex merge conflicts, rebase branches,
|
||||
merge manually, or undo and roll back commits, you'll need to use Git from
|
||||
merge manually, or undo and roll back commits, you musto use Git from
|
||||
the command line and then push your changes to the remote server.
|
||||
|
||||
This guide will help you get started with Git through the command line and can be your reference
|
||||
This guide helps you get started with Git through the command line and can be your reference
|
||||
for Git commands in the future. If you're only looking for a quick reference of Git commands, you
|
||||
can download the GitLab [Git Cheat Sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf).
|
||||
|
||||
|
|
@ -39,12 +39,12 @@ You don't need a GitLab account to use Git locally, but for the purpose of this
|
|||
recommend registering and signing into your account before starting. Some commands need a
|
||||
connection between the files in your computer and their version on a remote server.
|
||||
|
||||
You'll also need to open a [command shell](#command-shell) and have
|
||||
You must also open a [command shell](#command-shell) and have
|
||||
[Git installed](#install-git) in your computer.
|
||||
|
||||
### Command shell
|
||||
|
||||
To execute Git commands in your computer, you'll need to open a command shell (also known as command
|
||||
To execute Git commands in your computer, you must open a command shell (also known as command
|
||||
prompt, terminal, and command line) of your preference. Here are some suggestions:
|
||||
|
||||
- For macOS users:
|
||||
|
|
@ -66,18 +66,18 @@ computer:
|
|||
git --version
|
||||
```
|
||||
|
||||
If you have Git installed, the output will be:
|
||||
If you have Git installed, the output is:
|
||||
|
||||
```shell
|
||||
git version X.Y.Z
|
||||
```
|
||||
|
||||
If your computer doesn't recognize `git` as a command, you'll need to [install Git](../topics/git/how_to_install_git/index.md).
|
||||
If your computer doesn't recognize `git` as a command, you must [install Git](../topics/git/how_to_install_git/index.md).
|
||||
After that, run `git --version` again to verify whether it was correctly installed.
|
||||
|
||||
## Configure Git
|
||||
|
||||
To start using Git from your computer, you'll need to enter your credentials (user name and email)
|
||||
To start using Git from your computer, you must enter your credentials (user name and email)
|
||||
to identify you as the author of your work. The user name and email should match the ones you're
|
||||
using on GitLab.
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ git config --global --list
|
|||
```
|
||||
|
||||
The `--global` option tells Git to always use this information for anything you do on your system.
|
||||
If you omit `--global` or use `--local`, the configuration will be applied only to the current
|
||||
If you omit `--global` or use `--local`, the configuration is applied only to the current
|
||||
repository.
|
||||
|
||||
You can read more on how Git manages configurations in the
|
||||
|
|
@ -113,7 +113,7 @@ You have two options:
|
|||
|
||||
- Authenticate on a project-by-project basis through HTTPS, and enter your credentials every time
|
||||
you perform an operation between your computer and GitLab.
|
||||
- Authenticate through SSH once and GitLab won't ask your credentials every time you pull, push,
|
||||
- Authenticate through SSH once and GitLab no longer requests your credentials every time you pull, push,
|
||||
and clone.
|
||||
|
||||
To start the authentication process, we'll [clone](#clone-a-repository) an existing repository
|
||||
|
|
@ -121,8 +121,8 @@ to our computer:
|
|||
|
||||
- If you want to use **SSH** to authenticate, follow the instructions on the [SSH documentation](../ssh/README.md)
|
||||
to set it up before cloning.
|
||||
- If you want to use **HTTPS**, GitLab will request your user name and password:
|
||||
- If you have 2FA enabled for your account, you'll have to use a [Personal Access Token](../user/profile/personal_access_tokens.md)
|
||||
- If you want to use **HTTPS**, GitLab requests your user name and password:
|
||||
- If you have 2FA enabled for your account, you must use a [Personal Access Token](../user/profile/personal_access_tokens.md)
|
||||
with **read_repository** or **write_repository** permissions instead of your account's password.
|
||||
Create one before cloning.
|
||||
- If you don't have 2FA enabled, use your account's password.
|
||||
|
|
@ -161,11 +161,11 @@ Often, the word "repository" is shortened to "repo".
|
|||
### Fork
|
||||
|
||||
When you want to copy someone else's repository, you [**fork**](../user/project/repository/forking_workflow.md#creating-a-fork)
|
||||
the project. By forking it, you'll create a copy of the project into your own
|
||||
the project. By forking it, you create a copy of the project into your own
|
||||
namespace to have read and write permissions to modify the project files
|
||||
and settings.
|
||||
|
||||
For example, if you fork this project, <https://gitlab.com/gitlab-tests/sample-project/> into your namespace, you'll create your own copy of the repository in your namespace (`https://gitlab.com/your-namespace/sample-project/`). From there, you can clone it into your computer,
|
||||
For example, if you fork this project, <https://gitlab.com/gitlab-tests/sample-project/> into your namespace, you create your own copy of the repository in your namespace (`https://gitlab.com/your-namespace/sample-project/`). From there, you can clone it into your computer,
|
||||
work on its files, and (optionally) submit proposed changes back to the
|
||||
original repository if you'd like.
|
||||
|
||||
|
|
@ -185,19 +185,19 @@ After you saved a local copy of a repository and modified its files on your comp
|
|||
changes to GitLab. This is referred to as **pushing** to GitLab, as this is achieved by the command
|
||||
[`git push`](#send-changes-to-gitlabcom).
|
||||
|
||||
When the remote repository changes, your local copy will be behind it. You can update it with the new
|
||||
When the remote repository changes, your local copy is behind it. You can update it with the new
|
||||
changes in the remote repository.
|
||||
This is referred to as **pulling** from GitLab, as this is achieved by the command
|
||||
[`git pull`](#download-the-latest-changes-in-the-project).
|
||||
|
||||
## Basic Git commands
|
||||
|
||||
For the purposes of this guide, we will use this example project on GitLab.com:
|
||||
For the purposes of this guide, we use this example project on GitLab.com:
|
||||
[https://gitlab.com/gitlab-tests/sample-project/](https://gitlab.com/gitlab-tests/sample-project/).
|
||||
|
||||
To use it, log into GitLab.com and fork the example project into your
|
||||
namespace to have your own copy to playing with. Your sample
|
||||
project will be available under `https://gitlab.com/<your-namespace>/sample-project/`.
|
||||
project is available under `https://gitlab.com/<your-namespace>/sample-project/`.
|
||||
|
||||
You can also choose any other project to follow this guide. Then, replace the
|
||||
example URLs with your own project's.
|
||||
|
|
@ -213,7 +213,7 @@ To start working locally on an existing remote repository, clone it with the
|
|||
command `git clone <repository path>`. You can either clone it via [HTTPS](#clone-via-https) or [SSH](#clone-via-ssh), according to your preferred [authentication method](#git-authentication-methods).
|
||||
|
||||
You can find both paths (HTTPS and SSH) by navigating to your project's landing page
|
||||
and clicking **Clone**. GitLab will prompt you with both paths, from which you can copy
|
||||
and clicking **Clone**. GitLab prompts you with both paths, from which you can copy
|
||||
and paste in your command line.
|
||||
|
||||
For example, considering our [sample project](https://gitlab.com/gitlab-tests/sample-project/):
|
||||
|
|
@ -224,7 +224,7 @@ For example, considering our [sample project](https://gitlab.com/gitlab-tests/sa
|
|||
To get started, open a terminal window in the directory you wish to add the
|
||||
repository files into, and run one of the `git clone` commands as described below.
|
||||
|
||||
Both commands will download a copy of the files in a folder named after the project's
|
||||
Both commands download a copy of the files in a folder named after the project's
|
||||
name and preserve the connection with the remote repository.
|
||||
You can then navigate to the new directory with `cd sample-project` and start working on it
|
||||
locally.
|
||||
|
|
@ -253,8 +253,8 @@ git clone git@gitlab.com:gitlab-org/gitlab.git
|
|||
### Convert a local directory into a repository
|
||||
|
||||
When you have your files in a local folder and want to convert it into
|
||||
a repository, you'll need to _initialize_ the folder through the `git init`
|
||||
command. This will instruct Git to begin to track that directory as a
|
||||
a repository, you must _initialize_ the folder through the `git init`
|
||||
command. This instructs Git to begin to track that directory as a
|
||||
repository. To do so, open the terminal on the directory you'd like to convert
|
||||
and run:
|
||||
|
||||
|
|
@ -271,9 +271,9 @@ so that Git can upload your files into the correct project.
|
|||
|
||||
#### Add a remote repository
|
||||
|
||||
By "adding a remote repository" to your local directory you'll tell Git that
|
||||
By "adding a remote repository" to your local directory you tell Git that
|
||||
the path to that specific project in GitLab corresponds to that specific
|
||||
folder you have in your computer. This way, your local folder will be
|
||||
folder you have in your computer. This way, your local folder is
|
||||
identified by Git as the local content for that specific remote project.
|
||||
|
||||
To add a remote repository to your local copy:
|
||||
|
|
@ -320,7 +320,7 @@ The `-v` flag stands for verbose.
|
|||
|
||||
## Branching
|
||||
|
||||
If you want to add code to a project but you're not sure if it will work properly, or you're
|
||||
If you want to add code to a project but you're not sure if it works properly, or you're
|
||||
collaborating on the project with others, and don't want your work to get mixed up, it's a good idea
|
||||
to work on a different **branch**.
|
||||
|
||||
|
|
@ -384,7 +384,7 @@ git diff
|
|||
|
||||
### Add and commit local changes
|
||||
|
||||
You'll see any local changes in red when you type `git status`. These changes may
|
||||
Local changes are shown in red when you type `git status`. These changes may
|
||||
be new, modified, or deleted files/folders. Use `git add` to first stage (prepare)
|
||||
a local file/folder for committing. Then use `git commit` to commit (save) the staged
|
||||
files:
|
||||
|
|
@ -420,8 +420,8 @@ For example, to push your local commits to the _`master`_ branch of the _`origin
|
|||
git push origin master
|
||||
```
|
||||
|
||||
On certain occasions, Git won't allow you to push to your repository, and then
|
||||
you'll need to [force an update](../topics/git/git_rebase.md#force-push).
|
||||
On certain occasions, Git disallows pushes to your repository, and then
|
||||
you must [force an update](../topics/git/git_rebase.md#force-push).
|
||||
|
||||
NOTE:
|
||||
To create a merge request from a fork to an upstream repository, see the
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB |
|
|
@ -651,7 +651,7 @@ permissions on new projects when Auto DevOps is not enabled:
|
|||
The banner can be disabled for:
|
||||
|
||||
- A user, when they dismiss it themselves.
|
||||
- A project, by explicitly [disabling Auto DevOps](index.md#enablingdisabling-auto-devops).
|
||||
- A project, by explicitly [disabling Auto DevOps](index.md#enable-or-disable-auto-devops).
|
||||
- An entire GitLab instance:
|
||||
- By an administrator running the following in a Rails console:
|
||||
|
||||
|
|
|
|||
|
|
@ -34,27 +34,106 @@ For an introduction to Auto DevOps, watch [AutoDevOps in GitLab 11.0](https://yo
|
|||
|
||||
For requirements, read [Requirements for Auto DevOps](requirements.md) for more information.
|
||||
|
||||
For a developer's guide, read [Auto DevOps development guide](../../development/auto_devops.md).
|
||||
For GitLab contributors, see the [Auto DevOps development guide](../../development/auto_devops.md).
|
||||
|
||||
## Enabled by default
|
||||
## Enable or disable Auto DevOps
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41729) in GitLab 11.3.
|
||||
Auto DevOps is enabled by default for all projects in self-managed instances
|
||||
(as of [GitLab 11.3](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41729)),
|
||||
but not for GitLab SaaS instances.
|
||||
|
||||
On self-managed instances, Auto DevOps is enabled by default for all projects.
|
||||
It attempts to run on all pipelines in each project. An instance administrator can
|
||||
enable or disable this default in the
|
||||
[Auto DevOps settings](../../user/admin_area/settings/continuous_integration.md#auto-devops).
|
||||
Auto DevOps automatically disables in individual projects on their first pipeline failure,
|
||||
When first using Auto DevOps, review the [requirements](requirements.md) to
|
||||
ensure all the necessary components to make full use of Auto DevOps are
|
||||
available. First-time users should follow the [quick start guide](quick_start_guide.md).
|
||||
|
||||
NOTE:
|
||||
Auto DevOps is not enabled by default on GitLab.com.
|
||||
Depending on your instance type, you can enable or disable Auto DevOps at the
|
||||
following levels:
|
||||
|
||||
Since [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/issues/26655), Auto DevOps
|
||||
runs on pipelines automatically only if a [`Dockerfile` or matching buildpack](stages.md#auto-build)
|
||||
| Instance type | [Project](#at-the-project-level) | [Group](#at-the-group-level) | [Instance](#at-the-instance-level) (Admin Area) |
|
||||
|---------------------|------------------------|------------------------|------------------------|
|
||||
| GitLab SaaS | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
|
||||
| GitLab self-managed | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
|
||||
|
||||
When you enable AutoDevOps for your instance, it attempts to run on all
|
||||
pipelines in each project, but will automatically disable itself for individual
|
||||
projects on their first pipeline failure. An instance administrator can enable
|
||||
or disable this default in the [Auto DevOps settings](../../user/admin_area/settings/continuous_integration.md#auto-devops).
|
||||
|
||||
Since [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/issues/26655),
|
||||
Auto DevOps runs on pipelines automatically only if a [`Dockerfile` or matching buildpack](stages.md#auto-build)
|
||||
exists.
|
||||
|
||||
If a [CI/CD configuration file](../../ci/yaml/README.md) is present in the project,
|
||||
it continues to be used, whether or not Auto DevOps is enabled.
|
||||
If a [CI/CD configuration file](../../ci/yaml/README.md) is present in the
|
||||
project, it isn't changed and won't be affected by Auto DevOps.
|
||||
|
||||
### At the project level
|
||||
|
||||
When you enable Auto DevOps for a project, ensure that your project does not have a `.gitlab-ci.yml` present. If it exists, remove it before enabling Auto DevOps.
|
||||
|
||||
To enable it:
|
||||
|
||||
1. Go to your project's **Settings > CI/CD > Auto DevOps**.
|
||||
1. Select the **Default to Auto DevOps pipeline** checkbox to enable it.
|
||||
1. (Optional, but recommended) When enabling, you can add in the
|
||||
[base domain](#auto-devops-base-domain) Auto DevOps uses to
|
||||
[deploy your application](stages.md#auto-deploy),
|
||||
and choose the [deployment strategy](#deployment-strategy).
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
After enabling the feature, an Auto DevOps pipeline is triggered on the `master` branch.
|
||||
|
||||
### At the group level
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52447) in GitLab 11.10.
|
||||
|
||||
Only administrators and group owners can enable or disable Auto DevOps at the group level.
|
||||
|
||||
When enabling or disabling Auto DevOps at group level, group configuration is
|
||||
implicitly used for the subgroups and projects inside that group, unless Auto DevOps
|
||||
is specifically enabled or disabled on the subgroup or project.
|
||||
|
||||
To enable or disable Auto DevOps at the group level:
|
||||
|
||||
1. Go to your group's **Settings > CI/CD > Auto DevOps** page.
|
||||
1. Select the **Default to Auto DevOps pipeline** checkbox to enable it.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
### At the instance level **(FREE SELF)**
|
||||
|
||||
Even when disabled at the instance level, group owners and project maintainers
|
||||
can still enable Auto DevOps at the group and project level, respectively.
|
||||
|
||||
1. As an administrator, go to **Admin Area > Settings > CI/CD > Continuous Integration and Deployment**.
|
||||
1. Select **Default to Auto DevOps pipeline for all projects** to enable it.
|
||||
1. (Optional) You can set up the Auto DevOps [base domain](#auto-devops-base-domain),
|
||||
for Auto Deploy and Auto Review Apps to use.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
### Deployment strategy
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/38542) in GitLab 11.0.
|
||||
|
||||
You can change the deployment strategy used by Auto DevOps by visiting your
|
||||
project's **Settings > CI/CD > Auto DevOps**. The following options
|
||||
are available:
|
||||
|
||||
- **Continuous deployment to production**: Enables [Auto Deploy](stages.md#auto-deploy)
|
||||
with `master` branch directly deployed to production.
|
||||
- **Continuous deployment to production using timed incremental rollout**: Sets the
|
||||
[`INCREMENTAL_ROLLOUT_MODE`](customize.md#timed-incremental-rollout-to-production) variable
|
||||
to `timed`. Production deployments execute with a 5 minute delay between
|
||||
each increment in rollout.
|
||||
- **Automatic deployment to staging, manual deployment to production**: Sets the
|
||||
[`STAGING_ENABLED`](customize.md#deploy-policy-for-staging-and-production-environments) and
|
||||
[`INCREMENTAL_ROLLOUT_MODE`](customize.md#incremental-rollout-to-production) variables
|
||||
to `1` and `manual`. This means:
|
||||
|
||||
- `master` branch is directly deployed to staging.
|
||||
- Manual actions are provided for incremental rollout to production.
|
||||
|
||||
NOTE:
|
||||
Use the [blue-green deployment](../../ci/environments/incremental_rollouts.md#blue-green-deployment) technique
|
||||
to minimize downtime and risk.
|
||||
|
||||
## Quick start
|
||||
|
||||
|
|
@ -179,83 +258,6 @@ to the Kubernetes pods running your application.
|
|||
|
||||
See [Auto DevOps requirements for Amazon ECS](requirements.md#auto-devops-requirements-for-amazon-ecs).
|
||||
|
||||
## Enabling/Disabling Auto DevOps
|
||||
|
||||
When first using Auto DevOps, review the [requirements](requirements.md) to ensure
|
||||
all the necessary components to make full use of Auto DevOps are available. First-time
|
||||
users should follow the [quick start guide](quick_start_guide.md).
|
||||
|
||||
GitLab.com users can enable or disable Auto DevOps only at the project level.
|
||||
Self-managed users can enable or disable Auto DevOps at the project, group, or
|
||||
instance level.
|
||||
|
||||
### At the project level
|
||||
|
||||
If enabling, check that your project does not have a `.gitlab-ci.yml`, or if one exists, remove it.
|
||||
|
||||
1. Go to your project's **Settings > CI/CD > Auto DevOps**.
|
||||
1. Select the **Default to Auto DevOps pipeline** checkbox to enable it.
|
||||
1. (Optional, but recommended) When enabling, you can add in the
|
||||
[base domain](#auto-devops-base-domain) Auto DevOps uses to
|
||||
[deploy your application](stages.md#auto-deploy),
|
||||
and choose the [deployment strategy](#deployment-strategy).
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
After enabling the feature, an Auto DevOps pipeline is triggered on the `master` branch.
|
||||
|
||||
### At the group level
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52447) in GitLab 11.10.
|
||||
|
||||
Only administrators and group owners can enable or disable Auto DevOps at the group level.
|
||||
|
||||
When enabling or disabling Auto DevOps at group level, group configuration is
|
||||
implicitly used for the subgroups and projects inside that group, unless Auto DevOps
|
||||
is specifically enabled or disabled on the subgroup or project.
|
||||
|
||||
To enable or disable Auto DevOps at the group level:
|
||||
|
||||
1. Go to your group's **Settings > CI/CD > Auto DevOps** page.
|
||||
1. Select the **Default to Auto DevOps pipeline** checkbox to enable it.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
### At the instance level (Administrators only)
|
||||
|
||||
Even when disabled at the instance level, group owners and project maintainers can still enable
|
||||
Auto DevOps at the group and project level, respectively.
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD > Continuous Integration and Deployment**.
|
||||
1. Select **Default to Auto DevOps pipeline for all projects** to enable it.
|
||||
1. (Optional) You can set up the Auto DevOps [base domain](#auto-devops-base-domain),
|
||||
for Auto Deploy and Auto Review Apps to use.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
### Deployment strategy
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/38542) in GitLab 11.0.
|
||||
|
||||
You can change the deployment strategy used by Auto DevOps by visiting your
|
||||
project's **Settings > CI/CD > Auto DevOps**. The following options
|
||||
are available:
|
||||
|
||||
- **Continuous deployment to production**: Enables [Auto Deploy](stages.md#auto-deploy)
|
||||
with `master` branch directly deployed to production.
|
||||
- **Continuous deployment to production using timed incremental rollout**: Sets the
|
||||
[`INCREMENTAL_ROLLOUT_MODE`](customize.md#timed-incremental-rollout-to-production) variable
|
||||
to `timed`. Production deployments execute with a 5 minute delay between
|
||||
each increment in rollout.
|
||||
- **Automatic deployment to staging, manual deployment to production**: Sets the
|
||||
[`STAGING_ENABLED`](customize.md#deploy-policy-for-staging-and-production-environments) and
|
||||
[`INCREMENTAL_ROLLOUT_MODE`](customize.md#incremental-rollout-to-production) variables
|
||||
to `1` and `manual`. This means:
|
||||
|
||||
- `master` branch is directly deployed to staging.
|
||||
- Manual actions are provided for incremental rollout to production.
|
||||
|
||||
NOTE:
|
||||
Use the [blue-green deployment](../../ci/environments/incremental_rollouts.md#blue-green-deployment) technique
|
||||
to minimize downtime and risk.
|
||||
|
||||
## Using multiple Kubernetes clusters
|
||||
|
||||
When using Auto DevOps, you can deploy different environments to
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ If you don't have Kubernetes or Prometheus installed, then
|
|||
[Auto Deploy](stages.md#auto-deploy), and [Auto Monitoring](stages.md#auto-monitoring)
|
||||
are skipped.
|
||||
|
||||
After all requirements are met, you can [enable Auto DevOps](index.md#enablingdisabling-auto-devops).
|
||||
After all requirements are met, you can [enable Auto DevOps](index.md#enable-or-disable-auto-devops).
|
||||
|
||||
## Auto DevOps requirements for Amazon ECS
|
||||
|
||||
|
|
|
|||
|
|
@ -737,7 +737,7 @@ GitLab provides some initial alerts for you after you install Prometheus:
|
|||
To use Auto Monitoring:
|
||||
|
||||
1. [Install and configure the Auto DevOps requirements](requirements.md).
|
||||
1. [Enable Auto DevOps](index.md#enablingdisabling-auto-devops), if you haven't done already.
|
||||
1. [Enable Auto DevOps](index.md#enable-or-disable-auto-devops), if you haven't done already.
|
||||
1. Navigate to your project's **{rocket}** **CI/CD > Pipelines** and click **Run Pipeline**.
|
||||
1. After the pipeline finishes successfully, open the
|
||||
[monitoring dashboard for a deployed environment](../../ci/environments/index.md#monitoring-environments)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ In this case, the feature branch would be `release-X-Y`. Assuming the `release-X
|
|||
|
||||

|
||||
|
||||
1. After you click **Create merge request**, you'll see an option to **Change branches**. Select that option.
|
||||
1. After you click **Create merge request**, an option to **Change branches** displays. Select that option.
|
||||
|
||||
1. In the **New Merge Request** screen, you can now select the **Source** and **Target** branches.
|
||||
In the screenshot shown,
|
||||
|
|
@ -73,10 +73,10 @@ we have selected `test-branch` as the source, and `release-13-0` as the target.
|
|||
From test-branch into release-13-0
|
||||
```
|
||||
|
||||
An entry like this confirms that your MR will **not** merge into master.
|
||||
An entry like this confirms your merge request's destination.
|
||||
|
||||
1. Make any additional changes in the **New Merge Request** screen, and click **Submit merge request**.
|
||||
1. In the new merge request, look for **Request to merge**. You'll see an entry similar to:
|
||||
1. In the new merge request, look for **Request to merge**. An entry similar to this displays:
|
||||
|
||||
```plaintext
|
||||
Request to merge test-branch into release-13-0
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ type: howto
|
|||
# Installing Git **(FREE)**
|
||||
|
||||
To begin contributing to GitLab projects,
|
||||
you will need to install the Git client on your computer.
|
||||
you must install the Git client on your computer.
|
||||
|
||||
This article will show you how to install Git on macOS, Ubuntu Linux and Windows.
|
||||
This article shows you how to install Git on macOS, Ubuntu Linux and Windows.
|
||||
|
||||
Information on [installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
||||
is also available at the official Git website.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ More information is also available on the [Git website](https://git-scm.com).
|
|||
|
||||
## Getting started
|
||||
|
||||
The following resources will help you get started with Git:
|
||||
The following resources can help you get started with Git:
|
||||
|
||||
- [Git-ing started with Git](https://www.youtube.com/watch?v=Ce5nz5n41z4),
|
||||
a video introduction to Git.
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ Git 2.22.0 or later is required.
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/2553) in GitLab 12.10.
|
||||
|
||||
Storing large binary files in Git is normally discouraged, because every large
|
||||
file added will be downloaded by everyone who clones or fetches changes
|
||||
file added is downloaded by everyone who clones or fetches changes
|
||||
thereafter. This is slow, if not a complete obstruction when working from a slow
|
||||
or unreliable internet connection.
|
||||
|
||||
Using partial clone with a file size filter solves this problem, by excluding
|
||||
troublesome large files from clones and fetches. When Git encounters a missing
|
||||
file, it will be downloaded on demand.
|
||||
file, it's downloaded on demand.
|
||||
|
||||
When cloning a repository, use the `--filter=blob:limit=<size>` argument. For example,
|
||||
to clone the repository excluding files larger than 1 megabyte:
|
||||
|
|
@ -58,7 +58,7 @@ Updating files: 100% (13008/13008), done.
|
|||
Filtering content: 100% (3/3), 131.24 MiB | 4.65 MiB/s, done.
|
||||
```
|
||||
|
||||
The output will be longer because Git will first clone the repository excluding
|
||||
The output is longer because Git first clones the repository excluding
|
||||
files larger than 1 megabyte, and second download any missing large files needed
|
||||
to checkout the `master` branch.
|
||||
|
||||
|
|
@ -109,8 +109,8 @@ For more details, see the Git documentation for
|
|||
## Filter by file path
|
||||
|
||||
WARNING:
|
||||
Partial Clone using `sparse` filters is experimental, slow, and will
|
||||
significantly increase Gitaly resource utilization when cloning and fetching.
|
||||
Partial Clone using `sparse` filters is experimental, slow, and
|
||||
significantly increases Gitaly resource utilization when cloning and fetching.
|
||||
|
||||
Deeper integration between Partial Clone and Sparse Checkout is being explored
|
||||
through the `--filter=sparse:oid=<blob-ish>` filter spec, but this is highly
|
||||
|
|
@ -143,7 +143,7 @@ For more details, see the Git documentation for
|
|||
```
|
||||
|
||||
1. **Create a new Git repository and fetch.** Support for `--filter=sparse:oid`
|
||||
using the clone command is incomplete, so we will emulate the clone command
|
||||
using the clone command is incomplete, so we emulate the clone command
|
||||
by hand, using `git init` and `git fetch`. Follow
|
||||
[issue tracking support for `--filter=sparse:oid`](https://gitlab.com/gitlab-org/git/-/issues/4)
|
||||
for updates.
|
||||
|
|
@ -171,7 +171,7 @@ For more details, see the Git documentation for
|
|||
|
||||
WARNING:
|
||||
Git integrations with `bash`, `zsh`, etc and editors that automatically
|
||||
show Git status information often run `git fetch` which will fetch the
|
||||
show Git status information often run `git fetch` which fetches the
|
||||
entire repository. You many need to disable or reconfigure these
|
||||
integrations.
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 6.1 KiB |
|
|
@ -27,7 +27,7 @@ From now on, every existing project and newly created ones that don't have a
|
|||
`.gitlab-ci.yml`, will use the Auto DevOps pipelines.
|
||||
|
||||
If you want to disable it for a specific project, you can do so in
|
||||
[its settings](../../../topics/autodevops/index.md#enablingdisabling-auto-devops).
|
||||
[its settings](../../../topics/autodevops/index.md#enable-or-disable-auto-devops).
|
||||
|
||||
## Maximum artifacts size **(FREE SELF)**
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 31 KiB |
|
|
@ -55,13 +55,12 @@ There are several components that work in concert for the Agent to accomplish Gi
|
|||
Agent which repositories to synchronize with the cluster.
|
||||
- A manifest repository that contains manifest files. Any changes to manifest files are applied to the cluster.
|
||||
|
||||
These repositories might be the same GitLab project or separate projects.
|
||||
You can use the same GitLab project or separate projects for configuration and manifest files, as follows:
|
||||
|
||||
NOTE:
|
||||
GitLab recommends you use the same GitLab project for the agent configuration
|
||||
and manifest repositories. Our backlog contains issues for adding support for
|
||||
- Single GitLab project (recommended): when you use a single repository to hold both the manifest and the configuration files, these projects can be either private or public, as you prefer.
|
||||
- Two GitLab projects: when you opt to use two different GitLab projects, one for manifest files, and another for configuration files, the manifests project must be private, while the configuration project can be either private or public. Our backlog contains issues for adding support for
|
||||
[private manifest repositories outside of the configuration project](https://gitlab.com/gitlab-org/gitlab/-/issues/220912) and
|
||||
[group level agents](https://gitlab.com/gitlab-org/gitlab/-/issues/283885).
|
||||
[group level agents](https://gitlab.com/gitlab-org/gitlab/-/issues/283885) in the future.
|
||||
|
||||
For more details, please refer to our [full architecture documentation](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/architecture.md#high-level-architecture) in the Agent project.
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ GitLab supports two different modes of file locking:
|
|||
Locks can be created by any person who has at least
|
||||
[Developer permissions](../permissions.md) to the repository.
|
||||
|
||||
Only the user who locked the file or directory can edit locked files. Others
|
||||
users will be prevented from modifying locked files by pushing, merging,
|
||||
or any other means, and will be shown an error like: `The path '.gitignore' is
|
||||
Only the user who locked the file or directory can edit locked files. Other
|
||||
users are prevented from modifying locked files by pushing, merging,
|
||||
or any other means, and are shown an error like: `The path '.gitignore' is
|
||||
locked by Administrator`.
|
||||
|
||||
## Exclusive file locks **(FREE)**
|
||||
|
|
@ -60,7 +60,7 @@ Before getting started, make sure you have [Git LFS installed](../../topics/git/
|
|||
git-lfs --version
|
||||
```
|
||||
|
||||
If it doesn't recognize this command, you'll have to install it. There are
|
||||
If it doesn't recognize this command, you must install it. There are
|
||||
several [installation methods](https://git-lfs.github.com/) that you can
|
||||
choose according to your OS. To install it with Homebrew:
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ brew install git-lfs
|
|||
|
||||
Once installed, **open your local repository in a terminal window** and
|
||||
install Git LFS in your repository. If you're sure that LFS is already installed,
|
||||
you can skip this step. If you're unsure, re-installing it won't do any harm:
|
||||
you can skip this step. If you're unsure, re-installing it does no harm:
|
||||
|
||||
```shell
|
||||
git lfs install
|
||||
|
|
@ -84,14 +84,14 @@ You need [Maintainer permissions](../permissions.md) to configure
|
|||
Exclusive File Locks for your project through the command line.
|
||||
|
||||
The first thing to do before using File Locking is to tell Git LFS which
|
||||
kind of files are lockable. The following command will store PNG files
|
||||
kind of files are lockable. The following command stores PNG files
|
||||
in LFS and flag them as lockable:
|
||||
|
||||
```shell
|
||||
git lfs track "*.png" --lockable
|
||||
```
|
||||
|
||||
After executing the above command a file named `.gitattributes` will be
|
||||
After executing the above command a file named `.gitattributes` is
|
||||
created or updated with the following content:
|
||||
|
||||
```shell
|
||||
|
|
@ -110,9 +110,9 @@ implements the LFS File Locking API). To do that you can edit the
|
|||
The `.gitattributes` file is key to the process and **must**
|
||||
be pushed to the remote repository for the changes to take effect.
|
||||
|
||||
After a file type has been registered as lockable, Git LFS will make
|
||||
them read-only on the file system automatically. This means you will
|
||||
need to **lock the file** before [editing it](#edit-lockable-files).
|
||||
After a file type has been registered as lockable, Git LFS makes
|
||||
them read-only on the file system automatically. This means you
|
||||
must **lock the file** before [editing it](#edit-lockable-files).
|
||||
|
||||
### Lock files
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ git lfs locks
|
|||
The output lists the locked files followed by the user who locked each of them
|
||||
and the files' IDs.
|
||||
|
||||
On the repository file tree, GitLab will display an LFS badge for files
|
||||
On the repository file tree, GitLab displays an LFS badge for files
|
||||
tracked by Git LFS plus a padlock icon on exclusively-locked files:
|
||||
|
||||

|
||||
|
|
@ -176,7 +176,7 @@ tracked by Git LFS plus a padlock icon on exclusively-locked files:
|
|||
You can also [view and remove existing locks](#view-and-remove-existing-locks) from the GitLab UI.
|
||||
|
||||
NOTE:
|
||||
When you rename an exclusively-locked file, the lock is lost. You'll have to
|
||||
When you rename an exclusively-locked file, the lock is lost. You must
|
||||
lock it again to keep it locked.
|
||||
|
||||
### Edit lockable files
|
||||
|
|
@ -204,7 +204,7 @@ or higher tiers.
|
|||
Default branch file and directory locks only apply to the default branch set in
|
||||
the project's settings (usually `master`).
|
||||
|
||||
Changes to locked files on the default branch will be blocked, including merge
|
||||
Changes to locked files on the default branch are blocked, including merge
|
||||
requests that modify locked files. Unlock the file to allow changes.
|
||||
|
||||
### Lock a file or a directory
|
||||
|
|
@ -216,10 +216,10 @@ To lock a file:
|
|||
|
||||

|
||||
|
||||
An **Unlock** button will be displayed if the file is already locked, and
|
||||
will be disabled if you do not have permission to unlock the file.
|
||||
An **Unlock** button is displayed if the file is already locked, and
|
||||
is disabled if you do not have permission to unlock the file.
|
||||
|
||||
If you did not lock the file, hovering your cursor over the button will show
|
||||
If you did not lock the file, hovering your cursor over the button shows
|
||||
who locked the file.
|
||||
|
||||
### View and remove existing locks
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ directory of your repository and push it to the default branch of your project.
|
|||
## Encoding Requirements
|
||||
|
||||
The `.gitattributes` file _must_ be encoded in UTF-8 and _must not_ contain a
|
||||
Byte Order Mark. If a different encoding is used, the file's contents will be
|
||||
Byte Order Mark. If a different encoding is used, the file's contents are
|
||||
ignored.
|
||||
|
||||
## Syntax Highlighting
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
|
@ -17,7 +17,7 @@ to accept merge requests without creating merge commits.
|
|||
|
||||
When the fast-forward merge
|
||||
([`--ff-only`](https://git-scm.com/docs/git-merge#git-merge---ff-only)) setting
|
||||
is enabled, no merge commits will be created and all merges are fast-forwarded,
|
||||
is enabled, no merge commits are created and all merges are fast-forwarded,
|
||||
which means that merging is only allowed if the branch can be fast-forwarded.
|
||||
|
||||
When a fast-forward merge is not possible, the user is given the option to rebase.
|
||||
|
|
@ -28,19 +28,19 @@ When a fast-forward merge is not possible, the user is given the option to rebas
|
|||
1. Select the **Fast-forward merge** option
|
||||
1. Hit **Save changes** for the changes to take effect
|
||||
|
||||
Now, when you visit the merge request page, you will be able to accept it
|
||||
Now, when you visit the merge request page, you can accept it
|
||||
**only if a fast-forward merge is possible**.
|
||||
|
||||

|
||||
|
||||
If a fast-forward merge is not possible but a conflict free rebase is possible,
|
||||
a rebase button will be offered.
|
||||
a rebase button is offered.
|
||||
|
||||

|
||||
|
||||
If the target branch is ahead of the source branch and a conflict free rebase is
|
||||
not possible, you need to rebase the
|
||||
source branch locally before you will be able to do a fast-forward merge.
|
||||
source branch locally before you can do a fast-forward merge.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 38 KiB |
|
|
@ -79,7 +79,7 @@ An individual user can be added as an approver for a project if they are a membe
|
|||
- The project's immediate parent group.
|
||||
- A group that has access to the project via a [share](../members/share_project_with_groups.md).
|
||||
|
||||
A group of users can also be added as approvers, though they will only count as approvers if
|
||||
A group of users can also be added as approvers, though they only count as approvers if
|
||||
they have direct membership to the group. In the future, group approvers may be
|
||||
[restricted to only groups with share access to the project](https://gitlab.com/gitlab-org/gitlab/-/issues/2048).
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ NOTE:
|
|||
The squashed commit in this example is followed by a merge commit, because the merge method for this repository uses a merge commit. You can disable merge commits in
|
||||
**Project Settings > General > Merge requests > Merge method > Fast-forward merge**.
|
||||
|
||||
The squashed commit's commit message will be either:
|
||||
The squashed commit's commit message is either:
|
||||
|
||||
- Taken from the first multi-line commit message in the merge.
|
||||
- The merge request's title if no multi-line commit message is found.
|
||||
|
|
@ -60,7 +60,7 @@ This way, the history of your base branch remains clean with
|
|||
meaningful commit messages and:
|
||||
|
||||
- It's simpler to [revert](revert_changes.md) if necessary.
|
||||
- The merged branch will retain the full commit history.
|
||||
- The merged branch retains the full commit history.
|
||||
|
||||
## Enabling squash for a merge request
|
||||
|
||||
|
|
@ -113,18 +113,18 @@ squashing can itself be considered equivalent to rebasing.
|
|||
|
||||
With Squash Commits Options you can configure the behavior of Squash and Merge for your project.
|
||||
To set it up, navigate to your project's **Settings > General** and expand **Merge requests**.
|
||||
You will find the following options to choose, which will affect existing and new merge requests
|
||||
You can choose from these options, which affect existing and new merge requests
|
||||
submitted to your project:
|
||||
|
||||
- **Do not allow**: users cannot use Squash and Merge to squash all the commits immediately before
|
||||
merging. The checkbox to enable or disable it will be unchecked and hidden from the users.
|
||||
- **Allow**: users will have the option to enable Squash and Merge on a merge request basis.
|
||||
The checkbox will be unchecked (disabled) by default, but and the user is allowed to enable it.
|
||||
- **Encourage**: users will have the option to enable Squash and Merge on a merge request basis.
|
||||
The checkbox will be checked (enabled) by default to encourage its use, but the user is allowed to
|
||||
merging. The checkbox to enable or disable it is unchecked and hidden from the users.
|
||||
- **Allow**: users can enable Squash and Merge on a merge request basis.
|
||||
The checkbox is unchecked (disabled) by default, but and the user is allowed to enable it.
|
||||
- **Encourage**: users can enable Squash and Merge on a merge request basis.
|
||||
The checkbox is checked (enabled) by default to encourage its use, but the user is allowed to
|
||||
disable it.
|
||||
- **Require**: Squash and Merge is enabled for all merge requests, so it will always be performed.
|
||||
The checkbox to enable or disable it will be checked and hidden from the users.
|
||||
- **Require**: Squash and Merge is enabled for all merge requests, so it is always performed.
|
||||
The checkbox to enable or disable it is checked and hidden from the users.
|
||||
|
||||
The Squash and Merge checkbox is displayed when you create a merge request and when you edit the description of an existing one, except when Squash Commit Options is set to **Do not allow** or **Require**.
|
||||
|
||||
|
|
|
|||
|
|
@ -96,18 +96,20 @@ As soon as a requirement is reopened, it no longer appears in the **Archived** t
|
|||
|
||||
## Search for a requirement
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212543) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212543) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
|
||||
> - Searching by status [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/224614) in GitLab 13.10.
|
||||
|
||||
You can search for a requirement from the requirements list page based on the following criteria:
|
||||
|
||||
- Requirement title
|
||||
- Title
|
||||
- Author's username
|
||||
- Status (satisfied, failed, or missing)
|
||||
|
||||
To search for a requirement:
|
||||
|
||||
1. In a project, go to **Requirements > List**.
|
||||
1. Select the **Search or filter results** field. A dropdown menu appears.
|
||||
1. Select the requirement author from the dropdown or enter plain text to search by requirement title.
|
||||
1. Select the requirement author or status from the dropdown or enter plain text to search by requirement title.
|
||||
1. Press <kbd>Enter</kbd> on your keyboard to filter the list.
|
||||
|
||||
You can also sort the requirements list by:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module Gitlab
|
|||
AggregatedMetricError = Class.new(StandardError)
|
||||
UnknownAggregationOperator = Class.new(AggregatedMetricError)
|
||||
UnknownAggregationSource = Class.new(AggregatedMetricError)
|
||||
DisallowedAggregationTimeFrame = Class.new(AggregatedMetricError)
|
||||
|
||||
DATABASE_SOURCE = 'database'
|
||||
REDIS_SOURCE = 'redis'
|
||||
|
|
@ -30,25 +31,38 @@ module Gitlab
|
|||
@recorded_at = recorded_at
|
||||
end
|
||||
|
||||
def all_time_data
|
||||
aggregated_metrics_data(start_date: nil, end_date: nil, time_frame: Gitlab::Utils::UsageData::ALL_TIME_TIME_FRAME_NAME)
|
||||
end
|
||||
|
||||
def monthly_data
|
||||
aggregated_metrics_data(**monthly_time_range)
|
||||
aggregated_metrics_data(**monthly_time_range.merge(time_frame: Gitlab::Utils::UsageData::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME))
|
||||
end
|
||||
|
||||
def weekly_data
|
||||
aggregated_metrics_data(**weekly_time_range)
|
||||
aggregated_metrics_data(**weekly_time_range.merge(time_frame: Gitlab::Utils::UsageData::SEVEN_DAYS_TIME_FRAME_NAME))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :aggregated_metrics, :recorded_at
|
||||
|
||||
def aggregated_metrics_data(start_date:, end_date:)
|
||||
def aggregated_metrics_data(start_date:, end_date:, time_frame:)
|
||||
aggregated_metrics.each_with_object({}) do |aggregation, data|
|
||||
next if aggregation[:feature_flag] && Feature.disabled?(aggregation[:feature_flag], default_enabled: :yaml, type: :development)
|
||||
next unless aggregation[:time_frame].include?(time_frame)
|
||||
|
||||
case aggregation[:source]
|
||||
when REDIS_SOURCE
|
||||
data[aggregation[:name]] = calculate_count_for_aggregation(aggregation: aggregation, start_date: start_date, end_date: end_date)
|
||||
if time_frame == Gitlab::Utils::UsageData::ALL_TIME_TIME_FRAME_NAME
|
||||
data[aggregation[:name]] = Gitlab::Utils::UsageData::FALLBACK
|
||||
Gitlab::ErrorTracking
|
||||
.track_and_raise_for_dev_exception(
|
||||
DisallowedAggregationTimeFrame.new("Aggregation time frame: 'all' is not allowed for aggregation with source: '#{REDIS_SOURCE}'")
|
||||
)
|
||||
else
|
||||
data[aggregation[:name]] = calculate_count_for_aggregation(aggregation: aggregation, start_date: start_date, end_date: end_date)
|
||||
end
|
||||
when DATABASE_SOURCE
|
||||
next unless Feature.enabled?('database_sourced_aggregated_metrics', default_enabled: false, type: :development)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,15 +55,15 @@ module Gitlab
|
|||
end
|
||||
|
||||
def time_period_to_human_name(time_period)
|
||||
return Gitlab::Utils::UsageData::ALL_TIME_PERIOD_HUMAN_NAME if time_period.blank?
|
||||
return Gitlab::Utils::UsageData::ALL_TIME_TIME_FRAME_NAME if time_period.blank?
|
||||
|
||||
start_date = time_period.first.to_date
|
||||
end_date = time_period.last.to_date
|
||||
|
||||
if (end_date - start_date).to_i > 7
|
||||
Gitlab::Utils::UsageData::MONTHLY_PERIOD_HUMAN_NAME
|
||||
Gitlab::Utils::UsageData::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME
|
||||
else
|
||||
Gitlab::Utils::UsageData::WEEKLY_PERIOD_HUMAN_NAME
|
||||
Gitlab::Utils::UsageData::SEVEN_DAYS_TIME_FRAME_NAME
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ module Gitlab
|
|||
.merge(compliance_unique_visits_data)
|
||||
.merge(search_unique_visits_data)
|
||||
.merge(redis_hll_counters)
|
||||
.deep_merge(aggregated_metrics_data)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -224,8 +225,7 @@ module Gitlab
|
|||
project_snippets: count(ProjectSnippet.where(last_28_days_time_period)),
|
||||
projects_with_alerts_created: distinct_count(::AlertManagement::Alert.where(last_28_days_time_period), :project_id)
|
||||
}.merge(
|
||||
snowplow_event_counts(last_28_days_time_period(column: :collector_tstamp)),
|
||||
aggregated_metrics_monthly
|
||||
snowplow_event_counts(last_28_days_time_period(column: :collector_tstamp))
|
||||
).tap do |data|
|
||||
data[:snippets] = add(data[:personal_snippets], data[:project_snippets])
|
||||
end
|
||||
|
|
@ -250,10 +250,7 @@ module Gitlab
|
|||
|
||||
def system_usage_data_weekly
|
||||
{
|
||||
counts_weekly: {
|
||||
}.merge(
|
||||
aggregated_metrics_weekly
|
||||
)
|
||||
counts_weekly: {}
|
||||
}
|
||||
end
|
||||
|
||||
|
|
@ -713,15 +710,13 @@ module Gitlab
|
|||
{ redis_hll_counters: ::Gitlab::UsageDataCounters::HLLRedisCounter.unique_events_data }
|
||||
end
|
||||
|
||||
def aggregated_metrics_monthly
|
||||
def aggregated_metrics_data
|
||||
{
|
||||
aggregated_metrics: aggregated_metrics.monthly_data
|
||||
}
|
||||
end
|
||||
|
||||
def aggregated_metrics_weekly
|
||||
{
|
||||
aggregated_metrics: aggregated_metrics.weekly_data
|
||||
counts_weekly: { aggregated_metrics: aggregated_metrics.weekly_data },
|
||||
counts_monthly: { aggregated_metrics: aggregated_metrics.monthly_data },
|
||||
counts: aggregated_metrics
|
||||
.all_time_data
|
||||
.to_h { |key, value| ["aggregate_#{key}".to_sym, value.round] }
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
operator: OR
|
||||
feature_flag: usage_data_code_review_aggregation
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: [
|
||||
'i_code_review_user_single_file_diffs',
|
||||
'i_code_review_user_create_mr',
|
||||
|
|
@ -54,6 +55,7 @@
|
|||
operator: OR
|
||||
feature_flag: usage_data_code_review_aggregation
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: [
|
||||
'i_code_review_user_single_file_diffs',
|
||||
'i_code_review_user_create_mr',
|
||||
|
|
@ -96,6 +98,7 @@
|
|||
operator: OR
|
||||
feature_flag: usage_data_code_review_aggregation
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: [
|
||||
'i_code_review_user_vs_code_api_request'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
# source: defines which datasource will be used to locate events that should be included in aggregated metric. Valid values are:
|
||||
# - database
|
||||
# - redis
|
||||
# time_frame: defines time frames for aggregated metrics:
|
||||
# - 7d - last 7 days
|
||||
# - 28d - last 28 days
|
||||
# - all - all historical available data, this time frame is not available for redis source
|
||||
# feature_flag: name of development feature flag that will be checked before metrics aggregation is performed.
|
||||
# Corresponding feature flag should have `default_enabled` attribute set to `false`.
|
||||
# This attribute is OPTIONAL and can be omitted, when `feature_flag` is missing no feature flag will be checked.
|
||||
|
|
@ -14,18 +18,22 @@
|
|||
- name: compliance_features_track_unique_visits_union
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: ['g_compliance_audit_events', 'g_compliance_dashboard', 'i_compliance_audit_events', 'a_compliance_audit_events_api', 'i_compliance_credential_inventory']
|
||||
- name: product_analytics_test_metrics_union
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: ['i_search_total', 'i_search_advanced', 'i_search_paid']
|
||||
- name: product_analytics_test_metrics_intersection
|
||||
operator: AND
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: ['i_search_total', 'i_search_advanced', 'i_search_paid']
|
||||
- name: incident_management_alerts_total_unique_counts
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: [
|
||||
'incident_management_alert_status_changed',
|
||||
'incident_management_alert_assigned',
|
||||
|
|
@ -35,6 +43,7 @@
|
|||
- name: incident_management_incidents_total_unique_counts
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: [
|
||||
'incident_management_incident_created',
|
||||
'incident_management_incident_reopened',
|
||||
|
|
@ -51,10 +60,11 @@
|
|||
- name: i_testing_paid_monthly_active_user_total
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events: [
|
||||
'i_testing_web_performance_widget_total',
|
||||
'i_testing_full_code_quality_report_total',
|
||||
'i_testing_group_code_coverage_visit_total',
|
||||
'i_testing_load_performance_widget_total',
|
||||
'i_testing_metrics_report_widget_total'
|
||||
]
|
||||
'i_testing_web_performance_widget_total',
|
||||
'i_testing_full_code_quality_report_total',
|
||||
'i_testing_group_code_coverage_visit_total',
|
||||
'i_testing_load_performance_widget_total',
|
||||
'i_testing_metrics_report_widget_total'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ module Gitlab
|
|||
|
||||
FALLBACK = -1
|
||||
DISTRIBUTED_HLL_FALLBACK = -2
|
||||
ALL_TIME_PERIOD_HUMAN_NAME = "all_time"
|
||||
WEEKLY_PERIOD_HUMAN_NAME = "weekly"
|
||||
MONTHLY_PERIOD_HUMAN_NAME = "monthly"
|
||||
ALL_TIME_TIME_FRAME_NAME = "all"
|
||||
SEVEN_DAYS_TIME_FRAME_NAME = "7d"
|
||||
TWENTY_EIGHT_DAYS_TIME_FRAME_NAME = "28d"
|
||||
|
||||
def count(relation, column = nil, batch: true, batch_size: nil, start: nil, finish: nil)
|
||||
if batch
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module SystemCheck
|
|||
def check_sidekiq_running
|
||||
$stdout.print "Running? ... "
|
||||
|
||||
if sidekiq_process_count > 0
|
||||
if sidekiq_worker_process_count > 0
|
||||
$stdout.puts "yes".color(:green)
|
||||
else
|
||||
$stdout.puts "no".color(:red)
|
||||
|
|
@ -31,15 +31,16 @@ module SystemCheck
|
|||
end
|
||||
|
||||
def only_one_sidekiq_running
|
||||
process_count = sidekiq_process_count
|
||||
return if process_count == 0
|
||||
worker_count = sidekiq_worker_process_count
|
||||
cluster_count = sidekiq_cluster_process_count
|
||||
return if worker_count == 0
|
||||
|
||||
$stdout.print 'Number of Sidekiq processes ... '
|
||||
$stdout.print 'Number of Sidekiq processes (cluster/worker) ... '
|
||||
|
||||
if process_count == 1
|
||||
$stdout.puts '1'.color(:green)
|
||||
if (cluster_count == 1 && worker_count > 0) || (cluster_count == 0 && worker_count == 1)
|
||||
$stdout.puts "#{cluster_count}/#{worker_count}".color(:green)
|
||||
else
|
||||
$stdout.puts "#{process_count}".color(:red)
|
||||
$stdout.puts "#{cluster_count}/#{worker_count}".color(:red)
|
||||
try_fixing_it(
|
||||
'sudo service gitlab stop',
|
||||
"sudo pkill -u #{gitlab_user} -f sidekiq",
|
||||
|
|
@ -50,9 +51,14 @@ module SystemCheck
|
|||
end
|
||||
end
|
||||
|
||||
def sidekiq_process_count
|
||||
def sidekiq_worker_process_count
|
||||
ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww))
|
||||
ps_ux.scan(/sidekiq \d+\.\d+\.\d+/).count
|
||||
ps_ux.lines.grep(/sidekiq \d+\.\d+\.\d+/).count
|
||||
end
|
||||
|
||||
def sidekiq_cluster_process_count
|
||||
ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww))
|
||||
ps_ux.lines.grep(/sidekiq-cluster/).count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19638,6 +19638,9 @@ msgstr ""
|
|||
msgid "Mirroring will only be available if the feature is included in the plan of the selected group or user."
|
||||
msgstr ""
|
||||
|
||||
msgid "Missing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Missing OAuth configuration for GitHub."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -25330,6 +25333,9 @@ msgstr ""
|
|||
msgid "Reports|An error occurred while loading report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reports|Base report parsing error:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reports|Class"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -25352,6 +25358,9 @@ msgstr[1] ""
|
|||
msgid "Reports|Failure"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reports|Head report parsing error:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reports|Identifier"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ FactoryBot.define do
|
|||
transient do
|
||||
files { { 'foo.txt' => 'content' } }
|
||||
message { 'Message' }
|
||||
# rubocop: disable FactoryBot/InlineAssociation
|
||||
# We need a persisted project so we can create commits and tags
|
||||
# in `commit` otherwise linting this factory with `build` strategy
|
||||
# will fail.
|
||||
project { create(:project, :repository) }
|
||||
# rubocop: enable FactoryBot/InlineAssociation
|
||||
|
||||
service do
|
||||
Files::MultiService.new(
|
||||
|
|
@ -44,14 +49,13 @@ FactoryBot.define do
|
|||
|
||||
trait :files do
|
||||
transient do
|
||||
files { raise ArgumentError.new("files is required") }
|
||||
message { 'Add files' }
|
||||
end
|
||||
end
|
||||
|
||||
trait :package do
|
||||
transient do
|
||||
path { raise ArgumentError.new("path is required") }
|
||||
path { 'pkg' }
|
||||
message { 'Add package' }
|
||||
files { { "#{path}/b.go" => "package b\nfunc Bye() { println(\"Goodbye world!\") }\n" } }
|
||||
end
|
||||
|
|
@ -64,7 +68,7 @@ FactoryBot.define do
|
|||
host_prefix { "#{::Gitlab.config.gitlab.host}/#{project.path_with_namespace}" }
|
||||
|
||||
url { name ? "#{host_prefix}/#{name}" : host_prefix }
|
||||
path { name.to_s + '/' }
|
||||
path { "#{name}/" }
|
||||
|
||||
files do
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ FactoryBot.define do
|
|||
p = attributes[:params]
|
||||
s = Packages::SemVer.parse(p.semver, prefixed: true)
|
||||
|
||||
raise ArgumentError.new("invalid sematic version: '#{p.semver}''") if !s && p.semver
|
||||
raise ArgumentError, "invalid sematic version: '#{p.semver}'" if !s && p.semver
|
||||
|
||||
new(p.mod, p.type, p.commit, name: p.name, semver: s, ref: p.ref)
|
||||
end
|
||||
|
||||
mod { create :go_module }
|
||||
mod { association(:go_module) }
|
||||
type { :commit }
|
||||
commit { mod.project.repository.head_commit }
|
||||
name { nil }
|
||||
|
|
@ -33,45 +33,11 @@ FactoryBot.define do
|
|||
mod.project.repository.tags
|
||||
.filter { |t| Packages::SemVer.match?(t.name, prefixed: true) }
|
||||
.map { |t| Packages::SemVer.parse(t.name, prefixed: true) }
|
||||
.max { |a, b| "#{a}" <=> "#{b}" }
|
||||
.max_by(&:to_s)
|
||||
.to_s
|
||||
end
|
||||
|
||||
params { OpenStruct.new(mod: mod, type: :ref, commit: commit, semver: name, ref: ref) }
|
||||
end
|
||||
|
||||
trait :pseudo do
|
||||
transient do
|
||||
prefix do
|
||||
# This provides a sane default value, but in reality the caller should
|
||||
# specify `prefix:`
|
||||
|
||||
# This does not take into account that `commit` may be before the
|
||||
# latest tag.
|
||||
|
||||
# Find 'latest' semver tag (does not actually use semver precedence rules)
|
||||
v = mod.project.repository.tags
|
||||
.filter { |t| Packages::SemVer.match?(t.name, prefixed: true) }
|
||||
.map { |t| Packages::SemVer.parse(t.name, prefixed: true) }
|
||||
.max { |a, b| "#{a}" <=> "#{b}" }
|
||||
|
||||
# Default if no semver tags exist
|
||||
next 'v0.0.0' unless v
|
||||
|
||||
# Valid pseudo-versions are:
|
||||
# vX.0.0-yyyymmddhhmmss-sha1337beef0, when no earlier tagged commit exists for X
|
||||
# vX.Y.Z-pre.0.yyyymmddhhmmss-sha1337beef0, when most recent prior tag is vX.Y.Z-pre
|
||||
# vX.Y.(Z+1)-0.yyyymmddhhmmss-sha1337beef0, when most recent prior tag is vX.Y.Z
|
||||
|
||||
v = v.with(patch: v.patch + 1) unless v.prerelease
|
||||
"#{v}.0"
|
||||
end
|
||||
end
|
||||
|
||||
type { :pseudo }
|
||||
name { "#{prefix}#{commit.committed_date.strftime('%Y%m%d%H%M%S')}-#{commit.sha[0..11]}" }
|
||||
|
||||
params { OpenStruct.new(mod: mod, type: :pseudo, commit: commit, name: name, semver: name) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ FactoryBot.define do
|
|||
initialize_with { new(attributes[:project], attributes[:name], attributes[:path]) }
|
||||
skip_create
|
||||
|
||||
project { create :project, :repository }
|
||||
project { association(:project, :repository) }
|
||||
|
||||
path { '' }
|
||||
name { "#{Settings.build_gitlab_go_url}/#{project.full_path}#{path.empty? ? '' : '/'}#{path}" }
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@ RSpec.describe 'factories' do
|
|||
[:ci_job_artifact, :gzip],
|
||||
[:ci_job_artifact, :correct_checksum],
|
||||
[:environment, :non_playable],
|
||||
[:go_module_commit, :files],
|
||||
[:go_module_commit, :package],
|
||||
[:go_module_version, :pseudo],
|
||||
[:composer_cache_file, :object_storage],
|
||||
[:debian_project_component_file, :object_storage],
|
||||
[:debian_project_distribution, :object_storage],
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ describe('File Review(s) utilities', () => {
|
|||
|
||||
it.each`
|
||||
mrReviews | files | fileReviews
|
||||
${{}} | ${[file1, file2]} | ${[false, false]}
|
||||
${{ abc: ['123'] }} | ${[file1, file2]} | ${[true, false]}
|
||||
${{ abc: ['098'] }} | ${[file1, file2]} | ${[false, true]}
|
||||
${{ def: ['123'] }} | ${[file1, file2]} | ${[false, false]}
|
||||
${{ abc: ['123'], def: ['098'] }} | ${[]} | ${[]}
|
||||
${{}} | ${[file1, file2]} | ${{ 123: false, '098': false }}
|
||||
${{ abc: ['123'] }} | ${[file1, file2]} | ${{ 123: true, '098': false }}
|
||||
${{ abc: ['098'] }} | ${[file1, file2]} | ${{ 123: false, '098': true }}
|
||||
${{ def: ['123'] }} | ${[file1, file2]} | ${{ 123: false, '098': false }}
|
||||
${{ abc: ['123'], def: ['098'] }} | ${[]} | ${{}}
|
||||
`(
|
||||
'returns $fileReviews based on the diff files in state and the existing reviews $reviews',
|
||||
({ mrReviews, files, fileReviews }) => {
|
||||
|
|
|
|||
|
|
@ -295,6 +295,27 @@ describe('Grouped test reports app', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with a report parsing errors', () => {
|
||||
beforeEach(() => {
|
||||
const reports = failedReport;
|
||||
reports.suites[0].suite_errors = {
|
||||
head: 'JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
|
||||
base: 'JUnit data parsing failed: string not matched',
|
||||
};
|
||||
setReports(reports);
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('renders the error messages', () => {
|
||||
expect(findSummaryDescription().text()).toContain(
|
||||
'JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
|
||||
);
|
||||
expect(findSummaryDescription().text()).toContain(
|
||||
'JUnit data parsing failed: string not matched',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with error', () => {
|
||||
beforeEach(() => {
|
||||
mockStore.state.isLoading = false;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import ArtifactsApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue';
|
||||
import Deployment from '~/vue_merge_request_widget/components/deployment/deployment.vue';
|
||||
import DeploymentList from '~/vue_merge_request_widget/components/deployment/deployment_list.vue';
|
||||
import MrWidgetPipeline from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
|
||||
import MrWidgetPipelineContainer from '~/vue_merge_request_widget/components/mr_widget_pipeline_container.vue';
|
||||
import { mockStore } from '../mock_data';
|
||||
|
|
@ -30,6 +29,8 @@ describe('MrWidgetPipelineContainer', () => {
|
|||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findDeploymentList = () => wrapper.findComponent(DeploymentList);
|
||||
|
||||
describe('when pre merge', () => {
|
||||
beforeEach(() => {
|
||||
factory();
|
||||
|
|
@ -57,6 +58,9 @@ describe('MrWidgetPipelineContainer', () => {
|
|||
|
||||
const deployments = wrapper.findAll('.mr-widget-extension .js-pre-deployment');
|
||||
|
||||
expect(findDeploymentList().exists()).toBe(true);
|
||||
expect(findDeploymentList().props('deployments')).toBe(mockStore.deployments);
|
||||
|
||||
expect(deployments.wrappers.map((x) => x.props())).toEqual(expectedProps);
|
||||
});
|
||||
});
|
||||
|
|
@ -102,6 +106,8 @@ describe('MrWidgetPipelineContainer', () => {
|
|||
|
||||
const deployments = wrapper.findAll('.mr-widget-extension .js-post-deployment');
|
||||
|
||||
expect(findDeploymentList().exists()).toBe(true);
|
||||
expect(findDeploymentList().props('deployments')).toBe(mockStore.postMergeDeployments);
|
||||
expect(deployments.wrappers.map((x) => x.props())).toEqual(expectedProps);
|
||||
});
|
||||
});
|
||||
|
|
@ -113,50 +119,4 @@ describe('MrWidgetPipelineContainer', () => {
|
|||
expect(wrapper.find(ArtifactsApp).isVisible()).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('with many deployments', () => {
|
||||
let deployments;
|
||||
let collapsibleExtension;
|
||||
|
||||
beforeEach(() => {
|
||||
deployments = [
|
||||
...mockStore.deployments,
|
||||
...mockStore.deployments.map((deployment) => ({
|
||||
...deployment,
|
||||
id: deployment.id + mockStore.deployments.length,
|
||||
})),
|
||||
];
|
||||
factory({
|
||||
mr: {
|
||||
...mockStore,
|
||||
deployments,
|
||||
},
|
||||
});
|
||||
collapsibleExtension = wrapper.find('[data-testid="mr-collapsed-deployments"]');
|
||||
});
|
||||
|
||||
it('renders them collapsed', () => {
|
||||
expect(collapsibleExtension.exists()).toBe(true);
|
||||
expect(trimText(collapsibleExtension.text())).toBe(
|
||||
`${deployments.length} environments impacted. View all environments.`,
|
||||
);
|
||||
});
|
||||
|
||||
it('shows them when clicked', async () => {
|
||||
const expectedProps = deployments.map((dep) =>
|
||||
expect.objectContaining({
|
||||
deployment: dep,
|
||||
showMetrics: false,
|
||||
}),
|
||||
);
|
||||
await collapsibleExtension.find('button').trigger('click');
|
||||
|
||||
const deploymentWrappers = collapsibleExtension.findAllComponents(Deployment);
|
||||
|
||||
expect(deploymentWrappers.wrappers.map((x) => x.props())).toEqual(expectedProps);
|
||||
deploymentWrappers.wrappers.forEach((x) => {
|
||||
expect(x.text()).toEqual(expect.any(String));
|
||||
expect(x.text()).not.toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { zip } from 'lodash';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import Deployment from '~/vue_merge_request_widget/components/deployment/deployment.vue';
|
||||
import DeploymentList from '~/vue_merge_request_widget/components/deployment/deployment_list.vue';
|
||||
import MrCollapsibleExtension from '~/vue_merge_request_widget/components/mr_collapsible_extension.vue';
|
||||
import { mockStore } from '../mock_data';
|
||||
|
||||
const DEFAULT_PROPS = {
|
||||
showVisualReviewAppLink: false,
|
||||
hasDeploymentMetrics: false,
|
||||
deploymentClass: 'js-pre-deployment',
|
||||
};
|
||||
|
||||
describe('~/vue_merge_request_widget/components/deployment/deployment_list.vue', () => {
|
||||
let wrapper;
|
||||
let propsData;
|
||||
|
||||
const factory = (props = {}) => {
|
||||
propsData = {
|
||||
...DEFAULT_PROPS,
|
||||
deployments: mockStore.deployments,
|
||||
...props,
|
||||
};
|
||||
wrapper = mount(DeploymentList, {
|
||||
propsData,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper?.destroy?.();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
describe('with few deployments', () => {
|
||||
beforeEach(() => {
|
||||
factory();
|
||||
});
|
||||
|
||||
it('shows all deployments', () => {
|
||||
const deploymentWrappers = wrapper.findAllComponents(Deployment);
|
||||
expect(wrapper.findComponent(MrCollapsibleExtension).exists()).toBe(false);
|
||||
expect(deploymentWrappers).toHaveLength(propsData.deployments.length);
|
||||
|
||||
zip(deploymentWrappers.wrappers, propsData.deployments).forEach(
|
||||
([deploymentWrapper, deployment]) => {
|
||||
expect(deploymentWrapper.props('deployment')).toEqual(deployment);
|
||||
expect(deploymentWrapper.props()).toMatchObject({
|
||||
showVisualReviewApp: DEFAULT_PROPS.showVisualReviewAppLink,
|
||||
showMetrics: DEFAULT_PROPS.hasDeploymentMetrics,
|
||||
});
|
||||
expect(deploymentWrapper.classes(DEFAULT_PROPS.deploymentClass)).toBe(true);
|
||||
expect(deploymentWrapper.text()).toEqual(expect.any(String));
|
||||
expect(deploymentWrapper.text()).not.toBe('');
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('with many deployments', () => {
|
||||
let deployments;
|
||||
let collapsibleExtension;
|
||||
|
||||
beforeEach(() => {
|
||||
deployments = [
|
||||
...mockStore.deployments,
|
||||
...mockStore.deployments.map((deployment) => ({
|
||||
...deployment,
|
||||
id: deployment.id + mockStore.deployments.length,
|
||||
})),
|
||||
];
|
||||
factory({ deployments });
|
||||
|
||||
collapsibleExtension = wrapper.findComponent(MrCollapsibleExtension);
|
||||
});
|
||||
|
||||
it('shows collapsed deployments', () => {
|
||||
expect(collapsibleExtension.exists()).toBe(true);
|
||||
expect(trimText(collapsibleExtension.text())).toBe(
|
||||
`${deployments.length} environments impacted. View all environments.`,
|
||||
);
|
||||
});
|
||||
it('shows all deployments on click', async () => {
|
||||
await collapsibleExtension.find('button').trigger('click');
|
||||
const deploymentWrappers = wrapper.findAllComponents(Deployment);
|
||||
expect(deploymentWrappers).toHaveLength(deployments.length);
|
||||
|
||||
zip(deploymentWrappers.wrappers, propsData.deployments).forEach(
|
||||
([deploymentWrapper, deployment]) => {
|
||||
expect(deploymentWrapper.props('deployment')).toEqual(deployment);
|
||||
expect(deploymentWrapper.props()).toMatchObject({
|
||||
showVisualReviewApp: DEFAULT_PROPS.showVisualReviewAppLink,
|
||||
showMetrics: DEFAULT_PROPS.hasDeploymentMetrics,
|
||||
});
|
||||
expect(deploymentWrapper.classes(DEFAULT_PROPS.deploymentClass)).toBe(true);
|
||||
expect(deploymentWrapper.text()).toEqual(expect.any(String));
|
||||
expect(deploymentWrapper.text()).not.toBe('');
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -9,10 +9,50 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
let(:entity4) { '8b9a2671-2abf-4bec-a682-22f6a8f7bf31' }
|
||||
let(:end_date) { Date.current }
|
||||
let(:sources) { Gitlab::Usage::Metrics::Aggregates::Sources }
|
||||
let(:namespace) { described_class.to_s.deconstantize.constantize }
|
||||
|
||||
let_it_be(:recorded_at) { Time.current.to_i }
|
||||
|
||||
def aggregated_metric(name:, time_frame:, source: "redis", events: %w[event1 event2 event3], operator: "OR", feature_flag: nil)
|
||||
{
|
||||
name: name,
|
||||
source: source,
|
||||
events: events,
|
||||
operator: operator,
|
||||
time_frame: time_frame,
|
||||
feature_flag: feature_flag
|
||||
}.compact.with_indifferent_access
|
||||
end
|
||||
|
||||
context 'aggregated_metrics_data' do
|
||||
shared_examples 'db sourced aggregated metrics without database_sourced_aggregated_metrics feature' do
|
||||
before do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with disabled database_sourced_aggregated_metrics feature flag' do
|
||||
before do
|
||||
stub_feature_flags(database_sourced_aggregated_metrics: false)
|
||||
end
|
||||
|
||||
let(:aggregated_metrics) do
|
||||
[
|
||||
aggregated_metric(name: "gmau_2", source: "database", time_frame: time_frame)
|
||||
]
|
||||
end
|
||||
|
||||
it 'skips database sourced metrics', :aggregate_failures do
|
||||
results = {}
|
||||
params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
|
||||
|
||||
expect(sources::PostgresHll).not_to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3]))
|
||||
expect(aggregated_metrics_data).to eq(results)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'aggregated_metrics_data' do
|
||||
context 'no aggregated metric is defined' do
|
||||
it 'returns empty hash' do
|
||||
|
|
@ -31,37 +71,13 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
end
|
||||
end
|
||||
|
||||
context 'with disabled database_sourced_aggregated_metrics feature flag' do
|
||||
before do
|
||||
stub_feature_flags(database_sourced_aggregated_metrics: false)
|
||||
end
|
||||
|
||||
let(:aggregated_metrics) do
|
||||
[
|
||||
{ name: 'gmau_1', source: 'redis', events: %w[event3 event5], operator: "OR" },
|
||||
{ name: 'gmau_2', source: 'database', events: %w[event1 event2 event3], operator: "OR" }
|
||||
].map(&:with_indifferent_access)
|
||||
end
|
||||
|
||||
it 'skips database sourced metrics', :aggregate_failures do
|
||||
results = {
|
||||
'gmau_1' => 5
|
||||
}
|
||||
|
||||
params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
|
||||
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event3 event5])).and_return(5)
|
||||
expect(sources::PostgresHll).not_to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3]))
|
||||
expect(aggregated_metrics_data).to eq(results)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with AND operator' do
|
||||
let(:aggregated_metrics) do
|
||||
params = { source: datasource, operator: "AND", time_frame: time_frame }
|
||||
[
|
||||
{ name: 'gmau_1', source: 'redis', events: %w[event3 event5], operator: "AND" },
|
||||
{ name: 'gmau_2', source: 'database', events: %w[event1 event2 event3], operator: "AND" }
|
||||
].map(&:with_indifferent_access)
|
||||
aggregated_metric(**params.merge(name: "gmau_1", events: %w[event3 event5])),
|
||||
aggregated_metric(**params.merge(name: "gmau_2"))
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns the number of unique events recorded for every metric in aggregate', :aggregate_failures do
|
||||
|
|
@ -73,30 +89,30 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
|
||||
# gmau_1 data is as follow
|
||||
# |A| => 4
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(4)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(4)
|
||||
# |B| => 6
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event5')).and_return(6)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event5')).and_return(6)
|
||||
# |A + B| => 8
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event3 event5])).and_return(8)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event3 event5])).and_return(8)
|
||||
# Exclusion inclusion principle formula to calculate intersection of 2 sets
|
||||
# |A & B| = (|A| + |B|) - |A + B| => (4 + 6) - 8 => 2
|
||||
|
||||
# gmau_2 data is as follow:
|
||||
# |A| => 2
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event1')).and_return(2)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event1')).and_return(2)
|
||||
# |B| => 3
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event2')).and_return(3)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event2')).and_return(3)
|
||||
# |C| => 5
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(5)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(5)
|
||||
|
||||
# |A + B| => 4 therefore |A & B| = (|A| + |B|) - |A + B| => 2 + 3 - 4 => 1
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2])).and_return(4)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2])).and_return(4)
|
||||
# |A + C| => 6 therefore |A & C| = (|A| + |C|) - |A + C| => 2 + 5 - 6 => 1
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event3])).and_return(6)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event3])).and_return(6)
|
||||
# |B + C| => 7 therefore |B & C| = (|B| + |C|) - |B + C| => 3 + 5 - 7 => 1
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event2 event3])).and_return(7)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event2 event3])).and_return(7)
|
||||
# |A + B + C| => 8
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(8)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(8)
|
||||
# Exclusion inclusion principle formula to calculate intersection of 3 sets
|
||||
# |A & B & C| = (|A & B| + |A & C| + |B & C|) - (|A| + |B| + |C|) + |A + B + C|
|
||||
# (1 + 1 + 1) - (2 + 3 + 5) + 8 => 1
|
||||
|
|
@ -108,20 +124,17 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
context 'with OR operator' do
|
||||
let(:aggregated_metrics) do
|
||||
[
|
||||
{ name: 'gmau_1', source: 'redis', events: %w[event3 event5], operator: "OR" },
|
||||
{ name: 'gmau_2', source: 'database', events: %w[event1 event2 event3], operator: "OR" }
|
||||
].map(&:with_indifferent_access)
|
||||
aggregated_metric(name: "gmau_1", source: datasource, time_frame: time_frame, operator: "OR")
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns the number of unique events occurred for any metric in aggregate', :aggregate_failures do
|
||||
results = {
|
||||
'gmau_1' => 5,
|
||||
'gmau_2' => 3
|
||||
'gmau_1' => 5
|
||||
}
|
||||
params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
|
||||
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event3 event5])).and_return(5)
|
||||
expect(sources::PostgresHll).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(3)
|
||||
expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(5)
|
||||
expect(aggregated_metrics_data).to eq(results)
|
||||
end
|
||||
end
|
||||
|
|
@ -130,21 +143,22 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
let(:enabled_feature_flag) { 'test_ff_enabled' }
|
||||
let(:disabled_feature_flag) { 'test_ff_disabled' }
|
||||
let(:aggregated_metrics) do
|
||||
params = { source: datasource, time_frame: time_frame }
|
||||
[
|
||||
# represents stable aggregated metrics that has been fully released
|
||||
{ name: 'gmau_without_ff', source: 'redis', events: %w[event3_slot event5_slot], operator: "OR" },
|
||||
aggregated_metric(**params.merge(name: "gmau_without_ff")),
|
||||
# represents new aggregated metric that is under performance testing on gitlab.com
|
||||
{ name: 'gmau_enabled', source: 'redis', events: %w[event4], operator: "OR", feature_flag: enabled_feature_flag },
|
||||
aggregated_metric(**params.merge(name: "gmau_enabled", feature_flag: enabled_feature_flag)),
|
||||
# represents aggregated metric that is under development and shouldn't be yet collected even on gitlab.com
|
||||
{ name: 'gmau_disabled', source: 'redis', events: %w[event4], operator: "OR", feature_flag: disabled_feature_flag }
|
||||
].map(&:with_indifferent_access)
|
||||
aggregated_metric(**params.merge(name: "gmau_disabled", feature_flag: disabled_feature_flag))
|
||||
]
|
||||
end
|
||||
|
||||
it 'does not calculate data for aggregates with ff turned off' do
|
||||
skip_feature_flags_yaml_validation
|
||||
skip_default_enabled_yaml_check
|
||||
stub_feature_flags(enabled_feature_flag => true, disabled_feature_flag => false)
|
||||
allow(sources::RedisHll).to receive(:calculate_metrics_union).and_return(6)
|
||||
allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_return(6)
|
||||
|
||||
expect(aggregated_metrics_data).to eq('gmau_without_ff' => 6, 'gmau_enabled' => 6)
|
||||
end
|
||||
|
|
@ -156,31 +170,29 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
it 'raises error when unknown aggregation operator is used' do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([{ name: 'gmau_1', source: 'redis', events: %w[event1_slot], operator: "SUM" }])
|
||||
.and_return([aggregated_metric(name: 'gmau_1', source: datasource, operator: "SUM", time_frame: time_frame)])
|
||||
end
|
||||
|
||||
expect { aggregated_metrics_data }.to raise_error Gitlab::Usage::Metrics::Aggregates::UnknownAggregationOperator
|
||||
expect { aggregated_metrics_data }.to raise_error namespace::UnknownAggregationOperator
|
||||
end
|
||||
|
||||
it 'raises error when unknown aggregation source is used' do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([{ name: 'gmau_1', source: 'whoami', events: %w[event1_slot], operator: "AND" }])
|
||||
.and_return([aggregated_metric(name: 'gmau_1', source: 'whoami', time_frame: time_frame)])
|
||||
end
|
||||
|
||||
expect { aggregated_metrics_data }.to raise_error Gitlab::Usage::Metrics::Aggregates::UnknownAggregationSource
|
||||
expect { aggregated_metrics_data }.to raise_error namespace::UnknownAggregationSource
|
||||
end
|
||||
|
||||
it 're raises Gitlab::UsageDataCounters::HLLRedisCounter::EventError' do
|
||||
error = Gitlab::UsageDataCounters::HLLRedisCounter::EventError
|
||||
allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:calculate_events_union).and_raise(error)
|
||||
|
||||
it 'raises error when union is missing' do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([{ name: 'gmau_1', source: 'redis', events: %w[event1_slot], operator: "OR" }])
|
||||
.and_return([aggregated_metric(name: 'gmau_1', source: datasource, time_frame: time_frame)])
|
||||
end
|
||||
allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
|
||||
|
||||
expect { aggregated_metrics_data }.to raise_error error
|
||||
expect { aggregated_metrics_data }.to raise_error sources::UnionNotAvailable
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -192,7 +204,7 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
it 'rescues unknown aggregation operator error' do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([{ name: 'gmau_1', source: 'redis', events: %w[event1_slot], operator: "SUM" }])
|
||||
.and_return([aggregated_metric(name: 'gmau_1', source: datasource, operator: "SUM", time_frame: time_frame)])
|
||||
end
|
||||
|
||||
expect(aggregated_metrics_data).to eq('gmau_1' => -1)
|
||||
|
|
@ -201,20 +213,91 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
it 'rescues unknown aggregation source error' do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([{ name: 'gmau_1', source: 'whoami', events: %w[event1_slot], operator: "AND" }])
|
||||
.and_return([aggregated_metric(name: 'gmau_1', source: 'whoami', time_frame: time_frame)])
|
||||
end
|
||||
|
||||
expect(aggregated_metrics_data).to eq('gmau_1' => -1)
|
||||
end
|
||||
|
||||
it 'rescues Gitlab::UsageDataCounters::HLLRedisCounter::EventError' do
|
||||
error = Gitlab::UsageDataCounters::HLLRedisCounter::EventError
|
||||
allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:calculate_events_union).and_raise(error)
|
||||
|
||||
it 'rescues error when union is missing' do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([{ name: 'gmau_1', source: 'redis', events: %w[event1_slot], operator: "OR" }])
|
||||
.and_return([aggregated_metric(name: 'gmau_1', source: datasource, time_frame: time_frame)])
|
||||
end
|
||||
allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
|
||||
|
||||
expect(aggregated_metrics_data).to eq('gmau_1' => -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'database_sourced_aggregated_metrics' do
|
||||
let(:datasource) { namespace::DATABASE_SOURCE }
|
||||
|
||||
it_behaves_like 'aggregated_metrics_data'
|
||||
end
|
||||
|
||||
shared_examples 'redis_sourced_aggregated_metrics' do
|
||||
let(:datasource) { namespace::REDIS_SOURCE }
|
||||
|
||||
it_behaves_like 'aggregated_metrics_data' do
|
||||
context 'error handling' do
|
||||
let(:aggregated_metrics) { [aggregated_metric(name: 'gmau_1', source: datasource, time_frame: time_frame)] }
|
||||
let(:error) { Gitlab::UsageDataCounters::HLLRedisCounter::EventError }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
|
||||
end
|
||||
allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:calculate_events_union).and_raise(error)
|
||||
end
|
||||
|
||||
context 'development and test environment' do
|
||||
it 're raises Gitlab::UsageDataCounters::HLLRedisCounter::EventError' do
|
||||
expect { aggregated_metrics_data }.to raise_error error
|
||||
end
|
||||
end
|
||||
|
||||
context 'production' do
|
||||
it 'rescues Gitlab::UsageDataCounters::HLLRedisCounter::EventError' do
|
||||
stub_rails_env('production')
|
||||
|
||||
expect(aggregated_metrics_data).to eq('gmau_1' => -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.aggregated_metrics_all_time_data' do
|
||||
subject(:aggregated_metrics_data) { described_class.new(recorded_at).all_time_data }
|
||||
|
||||
let(:start_date) { nil }
|
||||
let(:end_date) { nil }
|
||||
let(:time_frame) { ['all'] }
|
||||
|
||||
it_behaves_like 'database_sourced_aggregated_metrics'
|
||||
it_behaves_like 'db sourced aggregated metrics without database_sourced_aggregated_metrics feature'
|
||||
|
||||
context 'redis sourced aggregated metrics' do
|
||||
let(:aggregated_metrics) { [aggregated_metric(name: 'gmau_1', time_frame: time_frame)] }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
|
||||
end
|
||||
end
|
||||
|
||||
context 'development and test environment' do
|
||||
it 'raises Gitlab::Usage::Metrics::Aggregates::DisallowedAggregationTimeFrame' do
|
||||
expect { aggregated_metrics_data }.to raise_error namespace::DisallowedAggregationTimeFrame
|
||||
end
|
||||
end
|
||||
|
||||
context 'production env' do
|
||||
it 'returns fallback value for unsupported time frame' do
|
||||
stub_rails_env('production')
|
||||
|
||||
expect(aggregated_metrics_data).to eq('gmau_1' => -1)
|
||||
end
|
||||
|
|
@ -232,32 +315,34 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
subject(:aggregated_metrics_data) { described_class.new(recorded_at).weekly_data }
|
||||
|
||||
let(:start_date) { 7.days.ago.to_date }
|
||||
let(:time_frame) { ['7d'] }
|
||||
|
||||
it_behaves_like 'aggregated_metrics_data'
|
||||
it_behaves_like 'database_sourced_aggregated_metrics'
|
||||
it_behaves_like 'redis_sourced_aggregated_metrics'
|
||||
it_behaves_like 'db sourced aggregated metrics without database_sourced_aggregated_metrics feature'
|
||||
end
|
||||
|
||||
describe '.aggregated_metrics_monthly_data' do
|
||||
subject(:aggregated_metrics_data) { described_class.new(recorded_at).monthly_data }
|
||||
|
||||
let(:start_date) { 4.weeks.ago.to_date }
|
||||
let(:time_frame) { ['28d'] }
|
||||
|
||||
it_behaves_like 'aggregated_metrics_data'
|
||||
it_behaves_like 'database_sourced_aggregated_metrics'
|
||||
it_behaves_like 'redis_sourced_aggregated_metrics'
|
||||
it_behaves_like 'db sourced aggregated metrics without database_sourced_aggregated_metrics feature'
|
||||
|
||||
context 'metrics union calls' do
|
||||
let(:aggregated_metrics) do
|
||||
[
|
||||
{ name: 'gmau_3', source: 'redis', events: %w[event1_slot event2_slot event3_slot event5_slot], operator: "AND" }
|
||||
].map(&:with_indifferent_access)
|
||||
end
|
||||
|
||||
it 'caches intermediate operations', :aggregate_failures do
|
||||
events = %w[event1 event2 event3 event5]
|
||||
allow_next_instance_of(described_class) do |instance|
|
||||
allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
|
||||
allow(instance).to receive(:aggregated_metrics)
|
||||
.and_return([aggregated_metric(name: 'gmau_1', events: events, operator: "AND", time_frame: time_frame)])
|
||||
end
|
||||
|
||||
params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
|
||||
|
||||
aggregated_metrics[0][:events].each do |event|
|
||||
events.each do |event|
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union)
|
||||
.with(params.merge(metric_names: event))
|
||||
.once
|
||||
|
|
@ -265,7 +350,7 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
end
|
||||
|
||||
2.upto(4) do |subset_size|
|
||||
aggregated_metrics[0][:events].combination(subset_size).each do |events|
|
||||
events.combination(subset_size).each do |events|
|
||||
expect(sources::RedisHll).to receive(:calculate_metrics_union)
|
||||
.with(params.merge(metric_names: events))
|
||||
.once
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll, :clean_
|
|||
|
||||
it 'persists serialized data in Redis' do
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
expect(redis).to receive(:set).with("#{metric_1}_weekly-#{recorded_at.to_i}", '{"141":1,"56":1}', ex: 120.hours)
|
||||
expect(redis).to receive(:set).with("#{metric_1}_7d-#{recorded_at.to_i}", '{"141":1,"56":1}', ex: 120.hours)
|
||||
end
|
||||
|
||||
save_aggregated_metrics
|
||||
|
|
@ -81,7 +81,7 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll, :clean_
|
|||
|
||||
it 'persists serialized data in Redis' do
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
expect(redis).to receive(:set).with("#{metric_1}_monthly-#{recorded_at.to_i}", '{"141":1,"56":1}', ex: 120.hours)
|
||||
expect(redis).to receive(:set).with("#{metric_1}_28d-#{recorded_at.to_i}", '{"141":1,"56":1}', ex: 120.hours)
|
||||
end
|
||||
|
||||
save_aggregated_metrics
|
||||
|
|
@ -93,7 +93,7 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll, :clean_
|
|||
|
||||
it 'persists serialized data in Redis' do
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
expect(redis).to receive(:set).with("#{metric_1}_all_time-#{recorded_at.to_i}", '{"141":1,"56":1}', ex: 120.hours)
|
||||
expect(redis).to receive(:set).with("#{metric_1}_all-#{recorded_at.to_i}", '{"141":1,"56":1}', ex: 120.hours)
|
||||
end
|
||||
|
||||
save_aggregated_metrics
|
||||
|
|
|
|||
|
|
@ -23,6 +23,22 @@ RSpec.describe 'aggregated metrics' do
|
|||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :have_known_time_frame do
|
||||
allowed_time_frames = [
|
||||
Gitlab::Utils::UsageData::ALL_TIME_TIME_FRAME_NAME,
|
||||
Gitlab::Utils::UsageData::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME,
|
||||
Gitlab::Utils::UsageData::SEVEN_DAYS_TIME_FRAME_NAME
|
||||
]
|
||||
|
||||
match do |aggregate|
|
||||
(aggregate[:time_frame] - allowed_time_frames).empty?
|
||||
end
|
||||
|
||||
failure_message do |aggregate|
|
||||
"Aggregate with name: `#{aggregate[:name]}` uses not allowed time_frame`#{aggregate[:time_frame] - allowed_time_frames}`"
|
||||
end
|
||||
end
|
||||
|
||||
let_it_be(:known_events) do
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.known_events
|
||||
end
|
||||
|
|
@ -38,10 +54,18 @@ RSpec.describe 'aggregated metrics' do
|
|||
expect(aggregated_metrics).to all has_known_source
|
||||
end
|
||||
|
||||
it 'all aggregated metrics has known source' do
|
||||
expect(aggregated_metrics).to all have_known_time_frame
|
||||
end
|
||||
|
||||
aggregated_metrics&.select { |agg| agg[:source] == Gitlab::Usage::Metrics::Aggregates::REDIS_SOURCE }&.each do |aggregate|
|
||||
context "for #{aggregate[:name]} aggregate of #{aggregate[:events].join(' ')}" do
|
||||
let_it_be(:events_records) { known_events.select { |event| aggregate[:events].include?(event[:name]) } }
|
||||
|
||||
it "does not include 'all' time frame for Redis sourced aggregate" do
|
||||
expect(aggregate[:time_frame]).not_to include(Gitlab::Utils::UsageData::ALL_TIME_TIME_FRAME_NAME)
|
||||
end
|
||||
|
||||
it "only refers to known events" do
|
||||
expect(aggregate[:events]).to all be_known_event
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1375,25 +1375,20 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.aggregated_metrics_weekly' do
|
||||
subject(:aggregated_metrics_payload) { described_class.aggregated_metrics_weekly }
|
||||
describe '.aggregated_metrics_data' do
|
||||
it 'uses ::Gitlab::Usage::Metrics::Aggregates::Aggregate methods', :aggregate_failures do
|
||||
expected_payload = {
|
||||
counts_weekly: { aggregated_metrics: { global_search_gmau: 123 } },
|
||||
counts_monthly: { aggregated_metrics: { global_search_gmau: 456 } },
|
||||
counts: { aggregate_global_search_gmau: 789 }
|
||||
}
|
||||
|
||||
it 'uses ::Gitlab::Usage::Metrics::Aggregates::Aggregate#weekly_data', :aggregate_failures do
|
||||
expect_next_instance_of(::Gitlab::Usage::Metrics::Aggregates::Aggregate) do |instance|
|
||||
expect(instance).to receive(:weekly_data).and_return(global_search_gmau: 123)
|
||||
expect(instance).to receive(:monthly_data).and_return(global_search_gmau: 456)
|
||||
expect(instance).to receive(:all_time_data).and_return(global_search_gmau: 789)
|
||||
end
|
||||
expect(aggregated_metrics_payload).to eq(aggregated_metrics: { global_search_gmau: 123 })
|
||||
end
|
||||
end
|
||||
|
||||
describe '.aggregated_metrics_monthly' do
|
||||
subject(:aggregated_metrics_payload) { described_class.aggregated_metrics_monthly }
|
||||
|
||||
it 'uses ::Gitlab::Usage::Metrics::Aggregates::Aggregate#monthly_data', :aggregate_failures do
|
||||
expect_next_instance_of(::Gitlab::Usage::Metrics::Aggregates::Aggregate) do |instance|
|
||||
expect(instance).to receive(:monthly_data).and_return(global_search_gmau: 123)
|
||||
end
|
||||
expect(aggregated_metrics_payload).to eq(aggregated_metrics: { global_search_gmau: 123 })
|
||||
expect(described_class.aggregated_metrics_data).to eq(expected_payload)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe SystemCheck::SidekiqCheck do
|
||||
describe '#multi_check' do
|
||||
def stub_ps_output(output)
|
||||
allow(Gitlab::Popen).to receive(:popen).with(%w(ps uxww)).and_return([output, nil])
|
||||
end
|
||||
|
||||
def expect_check_output(matcher)
|
||||
expect { subject.multi_check }.to output(matcher).to_stdout
|
||||
end
|
||||
|
||||
it 'fails when no worker processes are running' do
|
||||
stub_ps_output <<~PS
|
||||
root 2193947 0.9 0.1 146564 18104 ? Ssl 17:34 0:00 ruby bin/sidekiq-cluster * -P ...
|
||||
PS
|
||||
|
||||
expect_check_output include(
|
||||
'Running? ... no',
|
||||
'Please fix the error above and rerun the checks.'
|
||||
)
|
||||
end
|
||||
|
||||
it 'fails when more than one cluster process is running' do
|
||||
stub_ps_output <<~PS
|
||||
root 2193947 0.9 0.1 146564 18104 ? Ssl 17:34 0:00 ruby bin/sidekiq-cluster * -P ...
|
||||
root 2193948 0.9 0.1 146564 18104 ? Ssl 17:34 0:00 ruby bin/sidekiq-cluster * -P ...
|
||||
root 2193955 92.2 3.1 4675972 515516 ? Sl 17:34 0:13 sidekiq 5.2.9 ...
|
||||
PS
|
||||
|
||||
expect_check_output include(
|
||||
'Running? ... yes',
|
||||
'Number of Sidekiq processes (cluster/worker) ... 2/1',
|
||||
'Please fix the error above and rerun the checks.'
|
||||
)
|
||||
end
|
||||
|
||||
it 'succeeds when one cluster process and one or more worker processes are running' do
|
||||
stub_ps_output <<~PS
|
||||
root 2193947 0.9 0.1 146564 18104 ? Ssl 17:34 0:00 ruby bin/sidekiq-cluster * -P ...
|
||||
root 2193955 92.2 3.1 4675972 515516 ? Sl 17:34 0:13 sidekiq 5.2.9 ...
|
||||
root 2193956 92.2 3.1 4675972 515516 ? Sl 17:34 0:13 sidekiq 5.2.9 ...
|
||||
PS
|
||||
|
||||
expect_check_output <<~OUTPUT
|
||||
Running? ... yes
|
||||
Number of Sidekiq processes (cluster/worker) ... 1/2
|
||||
OUTPUT
|
||||
end
|
||||
|
||||
# TODO: Running without a cluster is deprecated and will be removed in GitLab 14.0
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/323225
|
||||
context 'when running without a cluster' do
|
||||
it 'fails when more than one worker process is running' do
|
||||
stub_ps_output <<~PS
|
||||
root 2193955 92.2 3.1 4675972 515516 ? Sl 17:34 0:13 sidekiq 5.2.9 ...
|
||||
root 2193956 92.2 3.1 4675972 515516 ? Sl 17:34 0:13 sidekiq 5.2.9 ...
|
||||
PS
|
||||
|
||||
expect_check_output include(
|
||||
'Running? ... yes',
|
||||
'Number of Sidekiq processes (cluster/worker) ... 0/2',
|
||||
'Please fix the error above and rerun the checks.'
|
||||
)
|
||||
end
|
||||
|
||||
it 'succeeds when one worker process is running' do
|
||||
stub_ps_output <<~PS
|
||||
root 2193955 92.2 3.1 4675972 515516 ? Sl 17:34 0:13 sidekiq 5.2.9 ...
|
||||
PS
|
||||
|
||||
expect_check_output <<~OUTPUT
|
||||
Running? ... yes
|
||||
Number of Sidekiq processes (cluster/worker) ... 0/1
|
||||
OUTPUT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
require Rails.root.join('db', 'post_migrate', '20210224150506_reschedule_artifact_expiry_backfill.rb')
|
||||
|
||||
RSpec.describe RescheduleArtifactExpiryBackfill, :migration do
|
||||
let(:migration_class) { Gitlab::BackgroundMigration::BackfillArtifactExpiryDate }
|
||||
let(:migration_name) { migration_class.to_s.demodulize }
|
||||
|
||||
before do
|
||||
table(:namespaces).create!(id: 123, name: 'test_namespace', path: 'test_namespace')
|
||||
table(:projects).create!(id: 123, name: 'sample_project', path: 'sample_project', namespace_id: 123)
|
||||
end
|
||||
|
||||
it 'correctly schedules background migrations' do
|
||||
first_artifact = create_artifact(job_id: 0, expire_at: nil, created_at: Date.new(2020, 06, 21))
|
||||
second_artifact = create_artifact(job_id: 1, expire_at: nil, created_at: Date.new(2020, 06, 21))
|
||||
create_artifact(job_id: 2, expire_at: Date.yesterday, created_at: Date.new(2020, 06, 21))
|
||||
create_artifact(job_id: 3, expire_at: nil, created_at: Date.new(2020, 06, 23))
|
||||
|
||||
Sidekiq::Testing.fake! do
|
||||
freeze_time do
|
||||
migrate!
|
||||
|
||||
expect(BackgroundMigrationWorker.jobs.size).to eq(1)
|
||||
expect(migration_name).to be_scheduled_migration_with_multiple_args(first_artifact.id, second_artifact.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_artifact(params)
|
||||
table(:ci_builds).create!(id: params[:job_id], project_id: 123)
|
||||
table(:ci_job_artifacts).create!(project_id: 123, file_type: 1, **params)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,63 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_context 'open merge request show action' do
|
||||
RSpec.shared_context 'merge request show action' do
|
||||
include Spec::Support::Helpers::Features::MergeRequestHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:note) { create(:note_on_merge_request, project: project, noteable: open_merge_request) }
|
||||
|
||||
let(:open_merge_request) do
|
||||
create(:merge_request, :opened, source_project: project, author: user)
|
||||
end
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :public, :repository) }
|
||||
let_it_be(:merge_request) { create(:merge_request, :opened, source_project: project, author: user) }
|
||||
let_it_be(:note) { create(:note_on_merge_request, project: project, noteable: merge_request) }
|
||||
|
||||
before do
|
||||
allow(view).to receive(:experiment_enabled?).and_return(false)
|
||||
allow(view).to receive(:current_user).and_return(user)
|
||||
assign(:project, project)
|
||||
assign(:merge_request, open_merge_request)
|
||||
assign(:merge_request, merge_request)
|
||||
assign(:note, note)
|
||||
assign(:noteable, open_merge_request)
|
||||
assign(:notes, [])
|
||||
assign(:pipelines, Ci::Pipeline.none)
|
||||
assign(:issuable_sidebar, serialize_issuable_sidebar(user, project, open_merge_request))
|
||||
assign(:noteable, merge_request)
|
||||
assign(:pipelines, [])
|
||||
assign(:issuable_sidebar, serialize_issuable_sidebar(user, project, merge_request))
|
||||
|
||||
preload_view_requirements(open_merge_request, note)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_context 'closed merge request show action' do
|
||||
include Devise::Test::ControllerHelpers
|
||||
include ProjectForksHelper
|
||||
include Spec::Support::Helpers::Features::MergeRequestHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:forked_project) { fork_project(project, user, repository: true) }
|
||||
let(:unlink_project) { Projects::UnlinkForkService.new(forked_project, user) }
|
||||
let(:note) { create(:note_on_merge_request, project: project, noteable: closed_merge_request) }
|
||||
|
||||
let(:closed_merge_request) do
|
||||
create(:closed_merge_request,
|
||||
source_project: forked_project,
|
||||
target_project: project,
|
||||
author: user)
|
||||
end
|
||||
|
||||
before do
|
||||
assign(:project, project)
|
||||
assign(:merge_request, closed_merge_request)
|
||||
assign(:commits_count, 0)
|
||||
assign(:note, note)
|
||||
assign(:noteable, closed_merge_request)
|
||||
assign(:notes, [])
|
||||
assign(:pipelines, Ci::Pipeline.none)
|
||||
assign(:issuable_sidebar, serialize_issuable_sidebar(user, project, closed_merge_request))
|
||||
|
||||
preload_view_requirements(closed_merge_request, note)
|
||||
|
||||
allow(view).to receive_messages(current_user: user,
|
||||
can?: true,
|
||||
current_application_settings: Gitlab::CurrentSettings.current_application_settings)
|
||||
preload_view_requirements(merge_request, note)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'projects/merge_requests/show.html.haml' do
|
||||
include Spec::Support::Helpers::Features::MergeRequestHelpers
|
||||
RSpec.describe 'projects/merge_requests/show.html.haml', :aggregate_failures do
|
||||
include_context 'merge request show action'
|
||||
|
||||
before do
|
||||
allow(view).to receive(:experiment_enabled?).and_return(false)
|
||||
merge_request.reload
|
||||
end
|
||||
|
||||
context 'when the merge request is open' do
|
||||
include_context 'open merge request show action'
|
||||
|
||||
it 'shows the "Mark as draft" button' do
|
||||
render
|
||||
|
||||
|
|
@ -22,20 +20,8 @@ RSpec.describe 'projects/merge_requests/show.html.haml' do
|
|||
end
|
||||
|
||||
context 'when the merge request is closed' do
|
||||
include_context 'closed merge request show action'
|
||||
|
||||
describe 'merge request assignee sidebar' do
|
||||
context 'when assignee is allowed to merge' do
|
||||
it 'does not show a warning icon' do
|
||||
closed_merge_request.update!(assignee_id: user.id)
|
||||
project.add_maintainer(user)
|
||||
assign(:issuable_sidebar, serialize_issuable_sidebar(user, project, closed_merge_request))
|
||||
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_css('.merge-icon')
|
||||
end
|
||||
end
|
||||
before do
|
||||
merge_request.close!
|
||||
end
|
||||
|
||||
it 'shows the "Reopen" button' do
|
||||
|
|
@ -46,15 +32,15 @@ RSpec.describe 'projects/merge_requests/show.html.haml' do
|
|||
expect(rendered).to have_css('a', visible: false, text: 'Close')
|
||||
end
|
||||
|
||||
it 'does not show the "Reopen" button when the source project does not exist' do
|
||||
unlink_project.execute
|
||||
closed_merge_request.reload
|
||||
preload_view_requirements(closed_merge_request, note)
|
||||
context 'when source project does not exist' do
|
||||
it 'does not show the "Reopen" button' do
|
||||
allow(merge_request).to receive(:source_project).and_return(nil)
|
||||
|
||||
render
|
||||
render
|
||||
|
||||
expect(rendered).to have_css('a', visible: false, text: 'Reopen')
|
||||
expect(rendered).to have_css('a', visible: false, text: 'Close')
|
||||
expect(rendered).to have_css('a', visible: false, text: 'Reopen')
|
||||
expect(rendered).to have_css('a', visible: false, text: 'Close')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||