Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-03-08 18:09:12 +00:00
parent 770d6dbfa7
commit 0179dc40d7
94 changed files with 1143 additions and 668 deletions

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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"

View File

@ -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();

View File

@ -124,7 +124,7 @@ export default function initDiffsApp(store) {
showSuggestPopover: this.showSuggestPopover,
fileByFileUserPreference: this.viewDiffsFileByFile,
defaultSuggestionCommitMessage: this.defaultSuggestionCommitMessage,
mrReviews: getReviewsForMergeRequest(mrPath),
rehydratedMrReviews: getReviewsForMergeRequest(mrPath),
},
});
},

View File

@ -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) {

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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" />

View File

@ -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)"
>

View File

@ -0,0 +1,5 @@
---
title: Fix Sidekiq system check for cluster mode
merge_request: 55530
author: Horst Prote
type: other

View File

@ -0,0 +1,5 @@
---
title: Reschedule artifact expiry backfill
merge_request: 55093
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Display parsing errors in test reports MR widget
merge_request: 55037
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Fix 'viewed' checkbox in single-file view mode
merge_request: 55922
author:
type: fixed

View File

@ -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

View File

@ -0,0 +1 @@
cc9f56a872cf5e9084e863adc599545754594fb03f30f18433923e0429986e39

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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

View File

@ -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.)

View File

@ -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.

View File

@ -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:

View File

@ -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

View File

@ -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" \

View File

@ -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

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -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.

View File

@ -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

View File

@ -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).

View File

@ -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 &amp; merge it to the main branch.
1. Your team lead reviews the code and merges it to the main branch.

View File

@ -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.

View File

@ -17,10 +17,10 @@ directly in the browser, youll 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -56,7 +56,7 @@ In this case, the feature branch would be `release-X-Y`. Assuming the `release-X
![Create merge request](img/create_merge_request_v13_1.png)
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

View File

@ -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.

View File

@ -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.

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -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)**

View File

@ -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.

View File

@ -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:
![LFS-Locked files](img/lfs_locked_files_v13_2.png)
@ -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:
![Locking file](img/file_lock.png)
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

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -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**.
![Fast forward merge request](img/ff_merge_mr.png)
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.
![Fast forward merge request](img/ff_merge_rebase.png)
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.
![Fast forward merge rebase locally](img/ff_merge_rebase_locally.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@ -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).

View File

@ -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**.

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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'
]

View File

@ -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'
]

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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
{

View File

@ -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

View File

@ -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}" }

View File

@ -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],

View File

@ -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 }) => {

View File

@ -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;

View File

@ -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('');
});
});
});
});

View File

@ -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('');
},
);
});
});
});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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