Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
25fdad39f5
commit
7912017a13
|
|
@ -397,6 +397,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/data/removals/ @gl-docsteam
|
||||
|
||||
^[Documentation Pages]
|
||||
# This block is managed by the rake script at lib/tasks/gitlab/tw/codeowners.rake, manual updates will be overwritten!
|
||||
# Begin rake-managed-docs-block
|
||||
/doc/administration/application_settings_cache.md @jglassman1
|
||||
/doc/administration/audit_event_streaming.md @eread
|
||||
/doc/administration/audit_events.md @eread
|
||||
|
|
@ -1032,6 +1034,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/user/todos.md @msedlakjakubowski
|
||||
/doc/user/usage_quotas.md @fneill
|
||||
/doc/user/workspace/ @lciutacu
|
||||
# End rake-managed-docs-block
|
||||
|
||||
[Authentication and Authorization]
|
||||
/app/assets/javascripts/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@
|
|||
.if-merge-request-labels-group-global-search: &if-merge-request-labels-group-global-search
|
||||
if: '$CI_MERGE_REQUEST_LABELS =~ /group::global search/'
|
||||
|
||||
.if-merge-request-labels-pipeline-revert: &if-merge-request-labels-pipeline-revert
|
||||
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:revert/'
|
||||
.if-merge-request-labels-pipeline-expedite-master-fixing: &if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
if: '$CI_MERGE_REQUEST_LABELS =~ /master:(foss-)?broken/ && $CI_MERGE_REQUEST_LABELS =~ /pipeline:expedite-master-fixing/'
|
||||
|
||||
.if-merge-request-labels-frontend-and-feature-flag: &if-merge-request-labels-frontend-and-feature-flag
|
||||
if: '$CI_MERGE_REQUEST_LABELS =~ /frontend/ && $CI_MERGE_REQUEST_LABELS =~ /feature flag/'
|
||||
|
|
@ -993,7 +993,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
|
|
@ -1102,7 +1102,7 @@
|
|||
when: never
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- <<: *if-merge-request-targeting-stable-branch
|
||||
allow_failure: true
|
||||
|
|
@ -1541,7 +1541,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
|
|
@ -1552,7 +1552,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-skip-undercoverage
|
||||
when: never
|
||||
|
|
@ -1587,7 +1587,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- if: '$SKIP_FLAKY_TESTS_AUTOMATICALLY == "true" || $RETRY_FAILED_TESTS_IN_NEW_PROCESS == "true"'
|
||||
changes: *code-backstage-patterns
|
||||
|
|
@ -1868,7 +1868,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-review-app
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
|
|
@ -1933,7 +1933,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-revert
|
||||
- <<: *if-merge-request-labels-pipeline-expedite-master-fixing
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-review-app
|
||||
when: manual
|
||||
|
|
|
|||
|
|
@ -2948,7 +2948,6 @@ Layout/LineLength:
|
|||
- 'lib/api/feature_flags.rb'
|
||||
- 'lib/api/files.rb'
|
||||
- 'lib/api/generic_packages.rb'
|
||||
- 'lib/api/go_proxy.rb'
|
||||
- 'lib/api/group_clusters.rb'
|
||||
- 'lib/api/group_import.rb'
|
||||
- 'lib/api/group_labels.rb'
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ Style/StringConcatenation:
|
|||
- 'ee/spec/support/shared_examples/models/geo_framework_registry_shared_examples.rb'
|
||||
- 'ee/spec/tasks/gitlab/license_rake_spec.rb'
|
||||
- 'lib/api/entities/tree_object.rb'
|
||||
- 'lib/api/go_proxy.rb'
|
||||
- 'lib/api/internal/kubernetes.rb'
|
||||
- 'lib/backup/files.rb'
|
||||
- 'lib/backup/manager.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
4b21b45f897007e0d3428353913edac8d1ecc422
|
||||
cdc87c3fefb4386c150cb4d71fcb4530d2b0501b
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ export default {
|
|||
v-else-if="conflictResolutionPath"
|
||||
:message="
|
||||
__(
|
||||
'You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}.',
|
||||
'You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}.',
|
||||
)
|
||||
"
|
||||
>
|
||||
|
|
@ -415,7 +415,7 @@ export default {
|
|||
</gl-sprintf>
|
||||
<gl-sprintf
|
||||
v-else
|
||||
:message="__('You can %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}.')"
|
||||
:message="__('You can %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}.')"
|
||||
>
|
||||
<template #resolveLocally="{ content }">
|
||||
<gl-button
|
||||
|
|
|
|||
|
|
@ -62,10 +62,15 @@ export const generateTreeList = (files) => {
|
|||
const split = file.new_path.split('/');
|
||||
|
||||
split.forEach((name, i) => {
|
||||
const parent = acc.treeEntries[split.slice(0, i).join('/')];
|
||||
let parent = acc.treeEntries[split.slice(0, i).join('/')];
|
||||
const path = `${parent ? `${parent.path}/` : ''}${name}`;
|
||||
const child = acc.treeEntries[path];
|
||||
|
||||
if (!acc.treeEntries[path]) {
|
||||
if (parent && !parent.tree) {
|
||||
parent = null;
|
||||
}
|
||||
|
||||
if (!child || !child.tree) {
|
||||
const type = path === file.new_path ? 'blob' : 'tree';
|
||||
acc.treeEntries[path] = {
|
||||
key: path,
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ export default class MergeRequestTabs {
|
|||
}
|
||||
}
|
||||
|
||||
tabShown(action, href) {
|
||||
tabShown(action, href, shouldScroll = true) {
|
||||
if (action !== this.currentTab && this.mergeRequestTabs) {
|
||||
this.currentTab = action;
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ export default class MergeRequestTabs {
|
|||
|
||||
$('.detail-page-description').renderGFM();
|
||||
|
||||
this.recallScroll(action);
|
||||
if (shouldScroll) this.recallScroll(action);
|
||||
} else if (action === this.currentAction) {
|
||||
// ContentTop is used to handle anything at the top of the page before the main content
|
||||
const mainContentContainer = document.querySelector('.content-wrapper');
|
||||
|
|
@ -350,7 +350,7 @@ export default class MergeRequestTabs {
|
|||
const scrollDestination = tabContentTop - mainContentTop - 51;
|
||||
|
||||
// scrollBehavior is only available in browsers that support scrollToOptions
|
||||
if ('scrollBehavior' in document.documentElement.style) {
|
||||
if ('scrollBehavior' in document.documentElement.style && shouldScroll) {
|
||||
window.scrollTo({
|
||||
top: scrollDestination,
|
||||
behavior: 'smooth',
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ export default {
|
|||
slotKeys() {
|
||||
return this.sortDirDesc ? ['form', 'comments'] : ['comments', 'form'];
|
||||
},
|
||||
isAppReady() {
|
||||
return !this.isLoading && !this.renderSkeleton && this.shouldShow;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
async isFetching() {
|
||||
|
|
@ -149,6 +152,15 @@ export default {
|
|||
this.discussionsCount.textContent = val;
|
||||
}
|
||||
},
|
||||
isAppReady: {
|
||||
handler(isReady) {
|
||||
if (!isReady) return;
|
||||
this.$nextTick(() => {
|
||||
window.mrTabs?.eventHub.$emit('NotesAppReady');
|
||||
});
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.discussionsCount = document.querySelector('.js-discussions-count');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import { mapGetters, mapActions, mapState } from 'vuex';
|
||||
import { scrollToElement, contentTop } from '~/lib/utils/common_utils';
|
||||
|
||||
function isOverviewPage() {
|
||||
return window.mrTabs?.currentAction === 'show';
|
||||
}
|
||||
|
||||
function getAllDiscussionElements() {
|
||||
const containerEl = window.mrTabs?.currentAction === 'diffs' ? '.diffs' : '.tab-pane.notes';
|
||||
const containerEl = isOverviewPage() ? '.tab-pane.notes' : '.diffs';
|
||||
return Array.from(
|
||||
document.querySelectorAll(
|
||||
`${containerEl} div[data-discussion-id]:not([data-discussion-resolved])`,
|
||||
|
|
@ -59,6 +63,14 @@ function getPreviousDiscussion() {
|
|||
|
||||
function handleJumpForBothPages(getDiscussion, ctx, fn, scrollOptions) {
|
||||
const discussion = getDiscussion();
|
||||
if (!isOverviewPage() && !discussion) {
|
||||
window.mrTabs?.eventHub.$once('NotesAppReady', () => {
|
||||
handleJumpForBothPages(getDiscussion, ctx, fn, scrollOptions);
|
||||
});
|
||||
window.mrTabs?.setCurrentAction('show');
|
||||
window.mrTabs?.tabShown('show', undefined, false);
|
||||
return;
|
||||
}
|
||||
const id = discussion.dataset.discussionId;
|
||||
ctx.expandDiscussion({ discussionId: id });
|
||||
scrollToElement(discussion, scrollOptions);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
@coverage_path = coverage_reports_project_merge_request_path(@project, @merge_request, format: :json) if @merge_request.has_coverage_reports?
|
||||
@update_current_user_path = expose_path(api_v4_user_preferences_path)
|
||||
@endpoint_metadata_url = endpoint_metadata_url(@project, @merge_request)
|
||||
@endpoint_diff_batch_url = endpoint_diff_batch_url(@project, @merge_request)
|
||||
|
||||
set_pipeline_variables
|
||||
|
||||
|
|
@ -549,12 +550,23 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
return render_404 unless can?(current_user, :read_build, merge_request.actual_head_pipeline)
|
||||
end
|
||||
|
||||
def show_whitespace
|
||||
current_user&.show_whitespace_in_diffs ? '0' : '1'
|
||||
end
|
||||
|
||||
def endpoint_metadata_url(project, merge_request)
|
||||
params = request.query_parameters.merge(view: 'inline', diff_head: true, w: current_user&.show_whitespace_in_diffs ? '0' : '1')
|
||||
params = request.query_parameters.merge(view: 'inline', diff_head: true, w: show_whitespace)
|
||||
|
||||
diffs_metadata_project_json_merge_request_path(project, merge_request, 'json', params)
|
||||
end
|
||||
|
||||
def endpoint_diff_batch_url(project, merge_request)
|
||||
per_page = current_user&.view_diffs_file_by_file ? '1' : '5'
|
||||
params = request.query_parameters.merge(view: 'inline', diff_head: true, w: show_whitespace, page: '0', per_page: per_page)
|
||||
|
||||
diffs_batch_project_json_merge_request_path(project, merge_request, 'json', params)
|
||||
end
|
||||
|
||||
def convert_date_to_epoch(date)
|
||||
Date.strptime(date, "%Y-%m-%d")&.to_time&.to_i if date
|
||||
rescue Date::Error, TypeError
|
||||
|
|
|
|||
|
|
@ -144,8 +144,7 @@ class SearchController < ApplicationController
|
|||
def check_single_commit_result?
|
||||
return false if params[:force_search_results]
|
||||
return false unless @project.present?
|
||||
# download_code project policy grants user the read_commit ability
|
||||
return false unless Ability.allowed?(current_user, :download_code, @project)
|
||||
return false unless Ability.allowed?(current_user, :read_code, @project)
|
||||
|
||||
query = params[:search].strip.downcase
|
||||
return false unless Commit.valid_hash?(query)
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ module SearchHelper
|
|||
hash[:project] = { id: @project.id, name: @project.name }
|
||||
hash[:project_metadata] = { issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project) }
|
||||
hash[:code_search] = search_scope.nil?
|
||||
hash[:ref] = @ref if @ref && can?(current_user, :download_code, @project)
|
||||
hash[:ref] = @ref if @ref && can?(current_user, :read_code, @project)
|
||||
end
|
||||
|
||||
hash[:scope] = search_scope if search_has_project? || search_has_group?
|
||||
|
|
@ -268,7 +268,7 @@ module SearchHelper
|
|||
|
||||
result = []
|
||||
|
||||
if can?(current_user, :download_code, @project)
|
||||
if can?(current_user, :read_code, @project)
|
||||
result.concat([
|
||||
{ category: "In this project", label: _("Files"), url: project_tree_path(@project, ref) },
|
||||
{ category: "In this project", label: _("Commits"), url: project_commits_path(@project, ref) }
|
||||
|
|
|
|||
|
|
@ -2934,10 +2934,6 @@ class Project < ApplicationRecord
|
|||
ci_cd_settings.keep_latest_artifact?
|
||||
end
|
||||
|
||||
def runner_token_expiration_interval
|
||||
ci_cd_settings&.runner_token_expiration_interval
|
||||
end
|
||||
|
||||
def group_runners_enabled?
|
||||
return false unless ci_cd_settings
|
||||
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
class BlobPolicy < BasePolicy
|
||||
delegate { @subject.project }
|
||||
|
||||
rule { can?(:download_code) }.enable :read_blob
|
||||
rule { can?(:read_code) }.enable :read_blob
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
class CommitPolicy < BasePolicy
|
||||
delegate { @subject.project }
|
||||
|
||||
rule { can?(:download_code) }.enable :read_commit
|
||||
rule { can?(:read_code) }.enable :read_commit
|
||||
rule { ~can?(:read_commit) }.prevent :create_note
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
- add_page_specific_style 'page_bundles/ci_status'
|
||||
|
||||
- add_page_startup_api_call @endpoint_metadata_url
|
||||
- if mr_action == 'diffs'
|
||||
- add_page_startup_api_call @endpoint_diff_batch_url
|
||||
|
||||
.merge-request{ data: { mr_action: mr_action, url: merge_request_path(@merge_request, format: :json), project_path: project_path(@merge_request.project), lock_version: @merge_request.lock_version } }
|
||||
- if moved_mr_sidebar_enabled?
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ metadata:
|
|||
description: Operations related to DevOps Research and Assessment (DORA) key metrics
|
||||
- name: environments
|
||||
description: Operations related to environments
|
||||
- name: error_tracking_client_keys
|
||||
description: Operations related to error tracking client keys
|
||||
- name: error_tracking_project_settings
|
||||
description: Operations related to error tracking project settings
|
||||
- name: feature_flags_user_lists
|
||||
|
|
@ -53,6 +55,8 @@ metadata:
|
|||
description: Operations related to Geo
|
||||
- name: geo_nodes
|
||||
description: Operations related Geo Nodes
|
||||
- name: go_proxy
|
||||
description: Operations related to Go Proxy
|
||||
- name: group_export
|
||||
description: Operations related to exporting groups
|
||||
- name: group_import
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@
|
|||
- [Bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) (Python)
|
||||
|
||||
NOTE:
|
||||
This change was originally planned for GitLab 15.0 and has been postponed.
|
||||
This change was originally planned for GitLab 15.0 and was postponed to GitLab 15.4.
|
||||
See [the removal notice](./removals.md#sast-analyzer-consolidation-and-cicd-template-changes) for further details.
|
||||
|
||||
These analyzers will be removed from the [GitLab-managed SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) and replaced with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
|
||||
They will no longer receive routine updates, except for security issues.
|
||||
Effective immediately, they will receive only security updates; other routine improvements or updates are not guaranteed.
|
||||
After these analyzers reach End of Support, no further updates will be provided.
|
||||
We will not delete container images previously published for these analyzers; any such change would be announced as a [deprecation, removal, or breaking change announcement](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes).
|
||||
|
||||
We will also remove Java from the scope of the [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) analyzer and replace it with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ exceptions:
|
|||
- ARN
|
||||
- ASCII
|
||||
- ASG
|
||||
- AST
|
||||
- AWS
|
||||
- BMP
|
||||
- BSD
|
||||
|
|
|
|||
|
|
@ -571,6 +571,7 @@ roadmap
|
|||
roadmaps
|
||||
rollout
|
||||
rollouts
|
||||
RSpec
|
||||
rsync
|
||||
rsynced
|
||||
rsyncing
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ GET /projects/:id/jobs/:job_id/artifacts
|
|||
Example request using the `PRIVATE-TOKEN` header:
|
||||
|
||||
```shell
|
||||
curl --output artifacts.zip --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts"
|
||||
curl --location --output artifacts.zip --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts"
|
||||
```
|
||||
|
||||
To use this in a [`script` definition](../ci/yaml/index.md#script) inside
|
||||
|
|
@ -90,7 +90,7 @@ Parameters
|
|||
Example request using the `PRIVATE-TOKEN` header:
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/main/download?job=test"
|
||||
curl --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/main/download?job=test"
|
||||
```
|
||||
|
||||
To use this in a [`script` definition](../ci/yaml/index.md#script) inside
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Verify
|
||||
group: Runner
|
||||
group: Runner SaaS
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: reference
|
||||
---
|
||||
|
|
|
|||
|
|
@ -7,31 +7,32 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Ruby style guide
|
||||
|
||||
This is a GitLab-specific style guide for Ruby code.
|
||||
This is a GitLab-specific style guide for Ruby code. Everything documented in this page can be [reopened for discussion](https://about.gitlab.com/handbook/values/#disagree-commit-and-disagree).
|
||||
|
||||
Generally, if a style is not covered by [existing RuboCop rules or style guides](../contributing/style_guides.md#ruby-rails-rspec), it shouldn't be a blocker.
|
||||
Before adding a new cop to enforce a given style, make sure to discuss it with your team.
|
||||
When the style is approved by a backend EM or by a BE staff eng, add a new section to this page to
|
||||
document the new rule. For every new guideline, add it in a new section and link the discussion from the section's
|
||||
[version history note](../documentation/versions.md#add-a-version-history-item)
|
||||
to provide context and serve as a reference.
|
||||
We use [RuboCop](../rubocop_development_guide.md) to enforce Ruby style guide rules.
|
||||
|
||||
See also [guidelines for reusing abstractions](../reusing_abstractions.md).
|
||||
Where a RuboCop rule is absent, refer to the following style guides as general guidelines to write idiomatic Ruby:
|
||||
|
||||
Everything listed here can be [reopened for discussion](https://about.gitlab.com/handbook/values/#disagree-commit-and-disagree).
|
||||
- [Ruby Style Guide](https://github.com/rubocop/ruby-style-guide).
|
||||
- [Rails Style Guide](https://github.com/rubocop/rails-style-guide).
|
||||
- [RSpec Style Guide](https://github.com/rubocop/rspec-style-guide).
|
||||
|
||||
## String literals quoting
|
||||
Generally, if a style is not covered by existing RuboCop rules or the above style guides, it shouldn't be a blocker.
|
||||
|
||||
Due to the sheer amount of work to rectify, we do not care whether string
|
||||
literals are single, or double quoted.
|
||||
Some styles we have decided [no one should not have a strong opinion on](#styles-we-have-no-opinion-on).
|
||||
|
||||
Previous discussions include:
|
||||
See also:
|
||||
|
||||
- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44234>
|
||||
- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36076>
|
||||
- <https://gitlab.com/gitlab-org/gitlab/-/issues/198046>
|
||||
- [Guidelines for reusing abstractions](../reusing_abstractions.md).
|
||||
- [Test-specific style guides and best practices](../testing_guide/index.md).
|
||||
|
||||
## Instance variable access using `attr_reader`
|
||||
## Styles we have no rule for
|
||||
|
||||
These styles are not backed by a RuboCop rule.
|
||||
|
||||
For every style added to this section, link the discussion from the section's [version history note](../documentation/versions.md#add-a-version-history-item) to provide context and serve as a reference.
|
||||
|
||||
### Instance variable access using `attr_reader`
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52351) in GitLab 14.1.
|
||||
|
||||
|
|
@ -84,11 +85,11 @@ Public attributes should only be used if they are accessed outside of the class.
|
|||
There is not a strong opinion on what strategy is used when attributes are only
|
||||
accessed internally, as long as there is consistency in related code.
|
||||
|
||||
## Newlines style guide
|
||||
### Newlines style guide
|
||||
|
||||
This style guide recommends best practices for newlines in Ruby code.
|
||||
In addition to the RuboCops `Layout/EmptyLinesAroundMethodBody` and `Cop/LineBreakAroundConditionalBlock` that enforce some newline styles, we have the following guidelines that are not backed by RuboCop.
|
||||
|
||||
### Rule: separate code with newlines only to group together related logic
|
||||
#### Rule: separate code with newlines only to group together related logic
|
||||
|
||||
```ruby
|
||||
# bad
|
||||
|
|
@ -111,9 +112,7 @@ def method
|
|||
end
|
||||
```
|
||||
|
||||
### Rule: separate code and block with newlines
|
||||
|
||||
#### Newline before block
|
||||
#### Rule: newline before block
|
||||
|
||||
```ruby
|
||||
# bad
|
||||
|
|
@ -136,35 +135,11 @@ def method
|
|||
end
|
||||
```
|
||||
|
||||
### Rule: Newline after block
|
||||
##### Exception: no need for a newline when code block starts or ends right inside another code block
|
||||
|
||||
```ruby
|
||||
# bad
|
||||
def method
|
||||
if issue.save
|
||||
issue.send_email
|
||||
end
|
||||
render json: issue
|
||||
end
|
||||
```
|
||||
|
||||
```ruby
|
||||
# good
|
||||
def method
|
||||
if issue.save
|
||||
issue.send_email
|
||||
end
|
||||
|
||||
render json: issue
|
||||
end
|
||||
```
|
||||
|
||||
#### Exception: no need for newline when code block starts or ends right inside another code block
|
||||
|
||||
```ruby
|
||||
# bad
|
||||
def method
|
||||
|
||||
if issue
|
||||
|
||||
if issue.valid?
|
||||
|
|
@ -172,7 +147,6 @@ def method
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
|
|
@ -186,3 +160,18 @@ def method
|
|||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Styles we have no opinion on
|
||||
|
||||
If a RuboCop rule is proposed and we choose not to add it, we should document that decision in this guide so it is more discoverable and link the relevant discussion as a reference.
|
||||
|
||||
### Quoting string literals
|
||||
|
||||
Due to the sheer amount of work to rectify, we do not care whether string
|
||||
literals are single or double-quoted.
|
||||
|
||||
Previous discussions include:
|
||||
|
||||
- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44234>
|
||||
- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36076>
|
||||
- <https://gitlab.com/gitlab-org/gitlab/-/issues/198046>
|
||||
|
|
|
|||
|
|
@ -108,117 +108,6 @@ pre-push:
|
|||
|
||||
For more information, check out [Lefthook documentation Skipping commands section](https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md#skipping-commands).
|
||||
|
||||
## Ruby, Rails, RSpec
|
||||
|
||||
Our codebase style is defined and enforced by [RuboCop](https://github.com/rubocop-hq/rubocop).
|
||||
|
||||
You can check for any offenses locally with `bundle exec rubocop --parallel`.
|
||||
On the CI, this is automatically checked by the `static-analysis` jobs.
|
||||
|
||||
In addition, you can [integrate RuboCop](../developing_with_solargraph.md) into
|
||||
supported IDEs using the [Solargraph](https://github.com/castwide/solargraph) gem.
|
||||
|
||||
For RuboCop rules that we have not taken a decision on yet, we follow the
|
||||
[Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide),
|
||||
[Rails Style Guide](https://github.com/rubocop-hq/rails-style-guide), and
|
||||
[RSpec Style Guide](https://github.com/rubocop-hq/rspec-style-guide) as general
|
||||
guidelines to write idiomatic Ruby/Rails/RSpec, but reviewers/maintainers should
|
||||
be tolerant and not too pedantic about style.
|
||||
|
||||
Similarly, some RuboCop rules are currently disabled, and for those,
|
||||
reviewers/maintainers must not ask authors to use one style or the other, as both
|
||||
are accepted. This isn't an ideal situation since this leaves space for
|
||||
[bike-shedding](https://en.wiktionary.org/wiki/bikeshedding), and ideally we
|
||||
should enable all RuboCop rules to avoid style-related
|
||||
discussions/nitpicking/back-and-forth in reviews. There are some styles that
|
||||
commonly come up in reviews that are not enforced, the
|
||||
[GitLab Ruby style guide](../backend/ruby_style_guide.md) includes a non-exhaustive
|
||||
list of these topics.
|
||||
|
||||
Additionally, we have a dedicated
|
||||
[newlines style guide](../newlines_styleguide.md), as well as dedicated
|
||||
[test-specific style guides and best practices](../testing_guide/index.md).
|
||||
|
||||
### Creating new RuboCop cops
|
||||
|
||||
Typically it is better for the linting rules to be enforced programmatically as it
|
||||
reduces the aforementioned [bike-shedding](https://en.wiktionary.org/wiki/bikeshedding).
|
||||
|
||||
To that end, we encourage creation of new RuboCop rules in the codebase.
|
||||
|
||||
We maintain Cops across several Ruby code bases, and not all of them are
|
||||
specific to the GitLab application.
|
||||
When creating a new cop that could be applied to multiple applications, we encourage you
|
||||
to add it to our [GitLab Styles](https://gitlab.com/gitlab-org/gitlab-styles) gem.
|
||||
If the Cop targets rules that only apply to the main GitLab application,
|
||||
it should be added to [GitLab](https://gitlab.com/gitlab-org/gitlab) instead.
|
||||
|
||||
### Cop grace period
|
||||
|
||||
A cop is in a "grace period" if it is enabled and has `Details: grace period` defined in its TODO YAML configuration.
|
||||
|
||||
On the default branch, all of the offenses from cops in the ["grace period"](../rake_tasks.md#run-rubocop-in-graceful-mode) will not fail the RuboCop CI job. The job will notify Slack in the `#f_rubocop` channel when offenses have been silenced in the scheduled pipeline. However, on merge request pipelines, the RuboCop job will fail.
|
||||
|
||||
A grace period can safely be lifted as soon as there are no warnings for 2 weeks in the `#f_rubocop` channel on Slack.
|
||||
|
||||
### Enabling a new cop
|
||||
|
||||
1. Enable the new cop in `.rubocop.yml` (if not already done via [`gitlab-styles`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles)).
|
||||
1. [Generate TODOs for the new cop](../rake_tasks.md#generate-initial-rubocop-todo-list).
|
||||
1. [Set the new cop to "grace period"](#cop-grace-period).
|
||||
1. Create an issue to fix TODOs and encourage Community contributions (via ~"good for new contributors" and/or ~"Seeking community contributions"). [See some examples](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=created_date&state=opened&label_name%5B%5D=good%20for%20new%20contributors&label_name%5B%5D=static%20code%20analysis&first_page_size=20).
|
||||
1. Create an issue to remove "grace period" after 2 weeks silence in `#f_rubocop` Slack channel. ([See an example](https://gitlab.com/gitlab-org/gitlab/-/issues/374903).)
|
||||
|
||||
### Silenced offenses
|
||||
|
||||
When offenses are silenced for cops in ["grace period"](#cop-grace-period),
|
||||
the `#f_rubocop` Slack channel receives a notification message every two hours.
|
||||
|
||||
To fix this issue:
|
||||
|
||||
1. Find cops with silenced offenses in the linked CI job.
|
||||
1. [Generate TODOs](../rake_tasks.md#generate-initial-rubocop-todo-list) for these cops.
|
||||
|
||||
#### RuboCop node pattern
|
||||
|
||||
When creating [node patterns](https://docs.rubocop.org/rubocop-ast/node_pattern.html) to match
|
||||
Ruby's AST, you can use [`scripts/rubocop-parse`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/rubocop-parse)
|
||||
to display the AST of a Ruby expression, to help you create the matcher.
|
||||
See also [!97024](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97024).
|
||||
|
||||
### Resolving RuboCop exceptions
|
||||
|
||||
When the number of RuboCop exceptions exceed the default [`exclude-limit` of 15](https://docs.rubocop.org/rubocop/1.2/usage/basic_usage.html#command-line-flags),
|
||||
we may want to resolve exceptions over multiple commits. To minimize confusion,
|
||||
we should track our progress through the exception list.
|
||||
|
||||
The preferred way to [generate the initial list or a list for specific RuboCop rules](../rake_tasks.md#generate-initial-rubocop-todo-list)
|
||||
is to run the Rake task `rubocop:todo:generate`:
|
||||
|
||||
```shell
|
||||
# Initial list
|
||||
bundle exec rake rubocop:todo:generate
|
||||
|
||||
# List for specific RuboCop rules
|
||||
bundle exec rake 'rubocop:todo:generate[Gitlab/NamespacedClass,Lint/Syntax]'
|
||||
```
|
||||
|
||||
This Rake task creates or updates the exception list in `.rubocop_todo/`. For
|
||||
example, the configuration for the RuboCop rule `Gitlab/NamespacedClass` is
|
||||
located in `.rubocop_todo/gitlab/namespaced_class.yml`.
|
||||
|
||||
Make sure to commit any changes in `.rubocop_todo/` after running the Rake task.
|
||||
|
||||
### Reveal existing RuboCop exceptions
|
||||
|
||||
To reveal existing RuboCop exceptions in the code that have been excluded via `.rubocop_todo.yml` and
|
||||
`.rubocop_todo/**/*.yml`, set the environment variable `REVEAL_RUBOCOP_TODO` to `1`.
|
||||
|
||||
This allows you to reveal existing RuboCop exceptions during your daily work cycle and fix them along the way.
|
||||
|
||||
NOTE:
|
||||
Define permanent `Exclude`s in `.rubocop.yml` instead of `.rubocop_todo/**/*.yml`.
|
||||
|
||||
## Database migrations
|
||||
|
||||
See the dedicated [Database Migrations Style Guide](../migration_style_guide.md).
|
||||
|
|
@ -231,6 +120,10 @@ See the dedicated [JS Style Guide](../fe_guide/style/javascript.md).
|
|||
|
||||
See the dedicated [SCSS Style Guide](../fe_guide/style/scss.md).
|
||||
|
||||
## Ruby
|
||||
|
||||
See the dedicated [Ruby Style Guide](../backend/ruby_style_guide.md).
|
||||
|
||||
## Go
|
||||
|
||||
See the dedicated [Go standards and style guidelines](../go_guide/index.md).
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ The following integration guides are internal. Some integrations require access
|
|||
- [Preventing transient bugs](transient/prevention-patterns.md)
|
||||
- [GitLab Application SLIs](application_slis/index.md)
|
||||
- [Spam protection and CAPTCHA development guide](spam_protection_and_captcha/index.md)
|
||||
- [RuboCop development guide](rubocop_development_guide.md)
|
||||
|
||||
## Other GitLab Development Kit (GDK) guides
|
||||
|
||||
|
|
|
|||
|
|
@ -146,9 +146,9 @@ merge request. This prevents `rspec fail-fast` duration from exceeding the avera
|
|||
|
||||
This number can be overridden by setting a CI/CD variable named `RSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD`.
|
||||
|
||||
## Faster feedback when reverting merge requests
|
||||
## Faster feedback for merge requests that fix a broken `master`
|
||||
|
||||
When you need to revert a merge request, to get accelerated feedback, you can add the `~pipeline:revert` label to your merge request.
|
||||
When you need to [fix a broken `master`](https://about.gitlab.com/handbook/engineering/workflow/#resolution-of-broken-master), you can add the `pipeline:expedite-master-fixing` label to expedite the pipelines that run on the merge request.
|
||||
|
||||
When this label is assigned, the following steps of the CI/CD pipeline are skipped:
|
||||
|
||||
|
|
@ -158,6 +158,8 @@ When this label is assigned, the following steps of the CI/CD pipeline are skipp
|
|||
|
||||
Apply the label to the merge request, and run a new pipeline for the MR.
|
||||
|
||||
Note that the merge request also needs to have the `master:broken` or `master:foss-broken` label set.
|
||||
|
||||
## Test jobs
|
||||
|
||||
We have dedicated jobs for each [testing level](../testing_guide/testing_levels.md) and each job runs depending on the
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ bundle exec rake rubocop:todo:generate\[Gitlab/NamespacedClass,Lint/Syntax\]
|
|||
|
||||
Some shells require brackets to be escaped or quoted.
|
||||
|
||||
See [Resolving RuboCop exceptions](contributing/style_guides.md#resolving-rubocop-exceptions)
|
||||
See [Resolving RuboCop exceptions](../development/rubocop_development_guide.md#resolving-rubocop-exceptions)
|
||||
on how to proceed from here.
|
||||
|
||||
### Run RuboCop in graceful mode
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
type: reference, dev
|
||||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# RuboCop rule development guide
|
||||
|
||||
Our codebase style is defined and enforced by [RuboCop](https://github.com/rubocop-hq/rubocop).
|
||||
|
||||
You can check for any offenses locally with `bundle exec rubocop --parallel`.
|
||||
On the CI, this is automatically checked by the `static-analysis` jobs.
|
||||
|
||||
In addition, you can [integrate RuboCop](developing_with_solargraph.md) into
|
||||
supported IDEs using the [Solargraph](https://github.com/castwide/solargraph) gem.
|
||||
|
||||
For RuboCop rules that we have not taken a decision on, follow the [Ruby style guide](backend/ruby_style_guide.md) to write idiomatic Ruby.
|
||||
|
||||
Reviewers/maintainers should be tolerant and not too pedantic about style.
|
||||
|
||||
Some RuboCop rules are disabled, and for those,
|
||||
reviewers/maintainers must not ask authors to use one style or the other, as both
|
||||
are accepted. This isn't an ideal situation because this leaves space for
|
||||
[bike-shedding](https://en.wiktionary.org/wiki/bikeshedding). Ideally we
|
||||
should enable all RuboCop rules to avoid style-related
|
||||
discussions, nitpicking, or back-and-forth in reviews. The
|
||||
[GitLab Ruby style guide](backend/ruby_style_guide.md) includes a non-exhaustive
|
||||
list of styles that commonly come up in reviews and are not enforced.
|
||||
|
||||
Additionally, we have dedicated
|
||||
[test-specific style guides and best practices](testing_guide/index.md).
|
||||
|
||||
## Creating new RuboCop cops
|
||||
|
||||
Typically it is better for the linting rules to be enforced programmatically as it
|
||||
reduces the aforementioned [bike-shedding](https://en.wiktionary.org/wiki/bikeshedding).
|
||||
|
||||
To that end, we encourage creation of new RuboCop rules in the codebase.
|
||||
|
||||
Before adding a new cop to enforce a given style, make sure to discuss it with your team.
|
||||
|
||||
We maintain cops across several Ruby code bases, and not all of them are
|
||||
specific to the GitLab application.
|
||||
When creating a new cop that could be applied to multiple applications, we encourage you
|
||||
to add it to our [`gitlab-styles`](https://gitlab.com/gitlab-org/gitlab-styles) gem.
|
||||
If the cop targets rules that only apply to the main GitLab application,
|
||||
it should be added to [GitLab](https://gitlab.com/gitlab-org/gitlab) instead.
|
||||
|
||||
## Cop grace period
|
||||
|
||||
A cop is in a _grace period_ if it is enabled and has `Details: grace period` defined in its TODO YAML configuration.
|
||||
|
||||
On the default branch, offenses from cops in the [grace period](rake_tasks.md#run-rubocop-in-graceful-mode) do not fail the RuboCop CI job. Instead, the job notifies the `#f_rubocop` Slack channel. However, on other branches, the RuboCop job fails.
|
||||
|
||||
A grace period can safely be lifted as soon as there are no warnings for 2 weeks in the `#f_rubocop` channel on Slack.
|
||||
|
||||
## Enabling a new cop
|
||||
|
||||
1. Enable the new cop in `.rubocop.yml` (if not already done via [`gitlab-styles`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles)).
|
||||
1. [Generate TODOs for the new cop](rake_tasks.md#generate-initial-rubocop-todo-list).
|
||||
1. [Set the new cop to `grace period`](#cop-grace-period).
|
||||
1. Create an issue to fix TODOs and encourage community contributions (via ~"good for new contributors" and/or ~"Seeking community contributions"). [See some examples](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=created_date&state=opened&label_name%5B%5D=good%20for%20new%20contributors&label_name%5B%5D=static%20code%20analysis&first_page_size=20).
|
||||
1. Create an issue to remove `grace period` after 2 weeks of silence in the `#f_rubocop` Slack channel. [See an example](https://gitlab.com/gitlab-org/gitlab/-/issues/374903).
|
||||
|
||||
## Silenced offenses
|
||||
|
||||
When offenses are silenced for cops in the [grace period](#cop-grace-period),
|
||||
the `#f_rubocop` Slack channel receives a notification message every 2 hours.
|
||||
|
||||
To fix this issue:
|
||||
|
||||
1. Find cops with silenced offenses in the linked CI job.
|
||||
1. [Generate TODOs](rake_tasks.md#generate-initial-rubocop-todo-list) for these cops.
|
||||
|
||||
### RuboCop node pattern
|
||||
|
||||
When creating [node patterns](https://docs.rubocop.org/rubocop-ast/node_pattern.html) to match
|
||||
Ruby's AST, you can use [`scripts/rubocop-parse`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/rubocop-parse).
|
||||
This displays the AST of a Ruby expression to help you create the matcher.
|
||||
See also [!97024](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97024).
|
||||
|
||||
## Resolving RuboCop exceptions
|
||||
|
||||
When the number of RuboCop exceptions exceeds the default [`exclude-limit` of 15](https://docs.rubocop.org/rubocop/1.2/usage/basic_usage.html#command-line-flags),
|
||||
we may want to resolve exceptions over multiple commits. To minimize confusion,
|
||||
we should track our progress through the exception list.
|
||||
|
||||
The preferred way to [generate the initial list or a list for specific RuboCop rules](rake_tasks.md#generate-initial-rubocop-todo-list)
|
||||
is to run the Rake task `rubocop:todo:generate`:
|
||||
|
||||
```shell
|
||||
# Initial list
|
||||
bundle exec rake rubocop:todo:generate
|
||||
|
||||
# List for specific RuboCop rules
|
||||
bundle exec rake 'rubocop:todo:generate[Gitlab/NamespacedClass,Lint/Syntax]'
|
||||
```
|
||||
|
||||
This Rake task creates or updates the exception list in `.rubocop_todo/`. For
|
||||
example, the configuration for the RuboCop rule `Gitlab/NamespacedClass` is
|
||||
located in `.rubocop_todo/gitlab/namespaced_class.yml`.
|
||||
|
||||
Make sure to commit any changes in `.rubocop_todo/` after running the Rake task.
|
||||
|
||||
## Reveal existing RuboCop exceptions
|
||||
|
||||
To reveal existing RuboCop exceptions in the code that have been excluded via `.rubocop_todo.yml` and
|
||||
`.rubocop_todo/**/*.yml`, set the environment variable `REVEAL_RUBOCOP_TODO` to `1`.
|
||||
|
||||
This allows you to reveal existing RuboCop exceptions during your daily work cycle and fix them along the way.
|
||||
|
||||
NOTE:
|
||||
Define permanent `Exclude`s in `.rubocop.yml` instead of `.rubocop_todo/**/*.yml`.
|
||||
|
|
@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344059) in GitLab 15.2 [with a flag](../../administration/feature_flags.md) named `incident_timeline`. Enabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/353426) in GitLab 15.3.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/353426) in GitLab 15.5. [Feature flag 'incident_timeline'](https://gitlab.com/gitlab-org/gitlab/-/issues/343386) removed.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/353426) in GitLab 15.5. [Feature flag `incident_timeline`](https://gitlab.com/gitlab-org/gitlab/-/issues/343386) removed.
|
||||
|
||||
Incident timelines are an important part of record keeping for incidents.
|
||||
Timelines can show executives and external viewers what happened during an incident,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
stage: Monitor
|
||||
group: Respond
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Incident management for Slack **(FREE SAAS)**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8545) in GitLab 15.6.
|
||||
|
||||
Many teams receive alerts and collaborate in real time during incidents in Slack.
|
||||
With the GitLab for Slack app:
|
||||
|
||||
- Create GitLab incidents from Slack.
|
||||
- Receive incident notifications.
|
||||
- Send important updates between Slack and GitLab incidents.
|
||||
|
||||
Incident management for Slack is initially only available for GitLab.com. Some of the functionality
|
||||
described might be available for
|
||||
[the self-managed Slack app](../../user/project/integrations/slack_slash_commands.md).
|
||||
To stay up to date, follow [epic 1211](https://gitlab.com/groups/gitlab-org/-/epics/1211).
|
||||
|
||||
## Setup and configuration
|
||||
|
||||
To be able to manage incidents from Slack:
|
||||
|
||||
1. Install the [GitLab for Slack app](../../user/project/integrations/gitlab_slack_application.md).
|
||||
Installing this application allows you to use slash commands in Slack to create and update GitLab incidents.
|
||||
|
||||
1. Enable [Slack notifications](../../user/project/integrations/slack.md). Be sure to enable
|
||||
notifications for `Issue` events, and to define a Slack channel to receive the relevant notifications.
|
||||
|
||||
## Manage an incident from Slack
|
||||
|
||||
Use the following slash commands in Slack to manage incidents
|
||||
|
||||
| Command | Description |
|
||||
| ---------------------------------- | ------------------------------------------ |
|
||||
| `/gitlab incident declare` | Creates an incident in GitLab. |
|
||||
| `/gitlab incident comment <text>` | Adds a comment on a GitLab incident. |
|
||||
| `/gitlab incident timeline <text>` | Adds a timeline event to a GitLab incident. |
|
||||
|
||||
After the Slack app for GitLab is configured, you can also use any of the [existing slash commands for Slack](../../user/project/integrations/gitlab_slack_application.md).
|
||||
|
||||
### Declare an incident
|
||||
|
||||
After you've configured the GitLab for Slack app, create incidents in GitLab from Slack
|
||||
with the `/gitlab incident declare` slash command.
|
||||
|
||||
To declare an incident:
|
||||
|
||||
1. In Slack, in any channel or DM, enter the `/gitlab incident declare` slash command.
|
||||
1. From the modal, select the relevant incident details, including:
|
||||
|
||||
- The incident title and description.
|
||||
- The project where the incident should be created.
|
||||
- The severity of the incident.
|
||||
|
||||
If there is an existing [incident template](incidents.md#create-incidents-automatically) for your
|
||||
project, that template is automatically applied to the description field. The template is applied
|
||||
only if the description field is empty.
|
||||
|
||||
You can also include GitLab [quick actions](../../user/project/quick_actions.md) in the description field.
|
||||
For example, typing `/link https://example.slack.com/archives/123456789 Dedicated Slack channel`
|
||||
adds a dedicated Slack channel to the incident you create. For a more complete list of applicable
|
||||
quick actions for incidents, see [Use GitLab quick actions](#use-gitlab-quick-actions).
|
||||
1. Optional. Add a link to an existing Zoom meeting.
|
||||
1. Select **Create**.
|
||||
|
||||
If the incident is successfully created, Slack shows a confirmation notification.
|
||||
|
||||
#### Use GitLab quick actions
|
||||
|
||||
Use [quick actions](../../user/project/quick_actions.md) in the description field when creating
|
||||
an incident from Slack to take additional actions in GitLab. The following quick actions might be the most relevant to you:
|
||||
|
||||
| Command | Description |
|
||||
| ------------------------ | ----------------------------------------- |
|
||||
| `/assign @user1 @user2` | Adds an assignee to the GitLab incident. |
|
||||
| `/label ~label1 ~label2` | Adds labels to the GitLab incident. |
|
||||
| `/link <URL> <text>` | Adds a link to a dedicated Slack channel, a runbook, or to any relevant resource to the `Related resources` section of an incident. |
|
||||
| `/zoom <URL>` | Adds a Zoom meeting link to the incident. |
|
||||
|
||||
### Comment on GitLab incidents
|
||||
|
||||
Comment on GitLab incidents from Slack with the `/gitlab incident comment <text>` slash command.
|
||||
|
||||
After you enter this slash command, Slack shows a prompt asking you to confirm which incident you'd
|
||||
like to post your comment to.
|
||||
|
||||
### Add a timeline event
|
||||
|
||||
Add a [timeline event](incident_timeline_events.md) to a GitLab incident from Slack with the
|
||||
`/gitlab incident timeline <text>` slash command.
|
||||
|
||||
After you enter this slash command, Slack shows a prompt asking you to confirm which incident you'd
|
||||
like to add your timeline event to.
|
||||
|
||||
### Close an incident
|
||||
|
||||
When your incident is fully resolved, close your incident from Slack using the `/gitlab incident close`
|
||||
slash command.
|
||||
|
||||
After you enter this slash command, Slack shows a prompt asking you to confirm which incident you'd
|
||||
like to close.
|
||||
|
||||
## Send GitLab incident notifications to Slack
|
||||
|
||||
If you have [enabled notifications](#setup-and-configuration) for issues, you should receive
|
||||
notifications to the selected Slack channel every time an incident is opened, closed, or updated.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No projects in the incident project dropdown list
|
||||
|
||||
If this happens, you might have not authorized GitLab to take actions on behalf of your Slack user.
|
||||
|
||||
Try executing a non-incident [Slack slash command](../../integration/slash_commands.md) to start the
|
||||
authorization flow. For more context, visit [issue 377548](https://gitlab.com/gitlab-org/gitlab/-/issues/377548).
|
||||
|
|
@ -1255,10 +1255,12 @@ In GitLab 15.4, GitLab SAST will no longer use the following analyzers:
|
|||
- [Bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) (Python)
|
||||
|
||||
NOTE:
|
||||
This change was originally planned for GitLab 15.0 and has been postponed.
|
||||
This change was originally planned for GitLab 15.0 and was postponed to GitLab 15.4.
|
||||
See [the removal notice](./removals.md#sast-analyzer-consolidation-and-cicd-template-changes) for further details.
|
||||
|
||||
These analyzers will be removed from the [GitLab-managed SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) and replaced with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
|
||||
They will no longer receive routine updates, except for security issues.
|
||||
Effective immediately, they will receive only security updates; other routine improvements or updates are not guaranteed.
|
||||
After these analyzers reach End of Support, no further updates will be provided.
|
||||
We will not delete container images previously published for these analyzers; any such change would be announced as a [deprecation, removal, or breaking change announcement](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes).
|
||||
|
||||
We will also remove Java from the scope of the [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) analyzer and replace it with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ threads. Some quick actions might not be available to all subscription tiers.
|
|||
| `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. |
|
||||
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. Also, mark both as related. |
|
||||
| `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. |
|
||||
| `/estimate <time>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set time estimate. For example, `/estimate 1mo 2w 3d 4h 5m`. Learn more about [time tracking](time_tracking.md). |
|
||||
| `/estimate <time>` or `/estimate_time <time>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set time estimate. For example, `/estimate 1mo 2w 3d 4h 5m`. Learn more about [time tracking](time_tracking.md). Alias `/estimate_time` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
|
||||
| `/health_status <value>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set [health status](issues/managing_issues.md#health-status). Valid options for `<value>` are `on_track`, `needs_attention`, and `at_risk` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213814) in GitLab 14.7). |
|
||||
| `/invite_email email1 email2` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add up to six email participants. This action is behind feature flag `issue_email_participants` and is not yet supported in issue templates. |
|
||||
| `/iteration *iteration:"iteration name"` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set iteration. For example, to set the `Late in July` iteration: `/iteration *iteration:"Late in July"` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196795) in GitLab 13.1). |
|
||||
|
|
@ -99,7 +99,7 @@ threads. Some quick actions might not be available to all subscription tiers.
|
|||
| `/remove_contacts [contact:email1@example.com] [contact:email2@example.com]` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove one or more [CRM contacts](../crm/index.md) ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73413) in GitLab 14.6). |
|
||||
| `/remove_due_date` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove due date. |
|
||||
| `/remove_epic` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove from epic. |
|
||||
| `/remove_estimate` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove time estimate. |
|
||||
| `/remove_estimate` or `/remove_time_estimate` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove time estimate. Alias `/remove_time_estimate` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
|
||||
| `/remove_iteration` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove iteration ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196795) in GitLab 13.1). |
|
||||
| `/remove_milestone` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove milestone. |
|
||||
| `/remove_parent_epic` | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Remove parent epic from epic ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10556) in GitLab 12.1). |
|
||||
|
|
@ -108,7 +108,7 @@ threads. Some quick actions might not be available to all subscription tiers.
|
|||
| `/reopen` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Reopen. |
|
||||
| `/severity <severity>` | **{check-circle}** Yes | **{check-circle}** No | **{check-circle}** No | Set the severity. Issue type must be `Incident`. Options for `<severity>` are `S1` ... `S4`, `critical`, `high`, `medium`, `low`, `unknown`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334045) in GitLab 14.2. |
|
||||
| `/shrug <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `¯\_(ツ)_/¯`. |
|
||||
| `/spend <time> [<date>]` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Add or subtract spent time. Optionally, specify the date that time was spent on. For example, `/spend 1mo 2w 3d 4h 5m 2018-08-26` or `/spend -1h 30m`. Learn more about [time tracking](time_tracking.md). |
|
||||
| `/spend <time> [<date>]` or `/spend_time <time> [<date>]` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Add or subtract spent time. Optionally, specify the date that time was spent on. For example, `/spend 1mo 2w 3d 4h 5m 2018-08-26` or `/spend -1h 30m`. Learn more about [time tracking](time_tracking.md). Alias `/spend_time` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
|
||||
| `/submit_review` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Submit a pending review ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8041) in GitLab 12.7). |
|
||||
| `/subscribe` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Subscribe to notifications. |
|
||||
| `/tableflip <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `(╯°□°)╯︵ ┻━┻`. |
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 444 KiB |
|
|
@ -62,8 +62,6 @@ to display, add a file to your repository.
|
|||
To preview Markdown content in the Web Editor, select the **Preview** tab.
|
||||
In this tab, you can see a live Markdown preview that updates as you type alongside your content.
|
||||
|
||||

|
||||
|
||||
To close the preview panel, do one of the following:
|
||||
|
||||
- Select the **Write** tab.
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ module API
|
|||
mount ::API::DeployTokens
|
||||
mount ::API::Deployments
|
||||
mount ::API::Environments
|
||||
mount ::API::ErrorTracking::ClientKeys
|
||||
mount ::API::ErrorTracking::ProjectSettings
|
||||
mount ::API::FeatureFlags
|
||||
mount ::API::FeatureFlagsUserLists
|
||||
|
|
@ -203,6 +204,7 @@ module API
|
|||
mount ::API::Files
|
||||
mount ::API::FreezePeriods
|
||||
mount ::API::Geo
|
||||
mount ::API::GoProxy
|
||||
mount ::API::GroupAvatar
|
||||
mount ::API::GroupClusters
|
||||
mount ::API::GroupExport
|
||||
|
|
@ -278,11 +280,9 @@ module API
|
|||
mount ::API::DebianGroupPackages
|
||||
mount ::API::DebianProjectPackages
|
||||
mount ::API::Discussions
|
||||
mount ::API::ErrorTracking::ClientKeys
|
||||
mount ::API::ErrorTracking::Collector
|
||||
mount ::API::Events
|
||||
mount ::API::GenericPackages
|
||||
mount ::API::GoProxy
|
||||
mount ::API::GroupBoards
|
||||
mount ::API::GroupContainerRepositories
|
||||
mount ::API::GroupDebianDistributions
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ module API
|
|||
end
|
||||
|
||||
class ClientKey < Grape::Entity
|
||||
expose :id
|
||||
expose :active
|
||||
expose :public_key
|
||||
expose :sentry_dsn
|
||||
expose :id, documentation: { type: 'integer', example: 1 }
|
||||
expose :active, documentation: { type: 'boolean' }
|
||||
expose :public_key, documentation: { type: 'string', example: 'glet_aa77551d849c083f76d0bc545ed053a3' }
|
||||
expose :sentry_dsn, documentation: { type: 'string', example: 'https://glet_aa77551d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
module API
|
||||
module Entities
|
||||
class GoModuleVersion < Grape::Entity
|
||||
expose :name, as: 'Version'
|
||||
expose :time, as: 'Time'
|
||||
expose :name, as: 'Version', documentation: { type: 'string', example: 'v1.0.0' }
|
||||
expose :time, as: 'Time', documentation: { type: 'string', example: '1617822312 -0600' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@ module API
|
|||
class ErrorTracking::ClientKeys < ::API::Base
|
||||
before { authenticate! }
|
||||
|
||||
ERROR_TRACKING_CLIENT_KEYS_TAGS = %w[error_tracking_client_keys].freeze
|
||||
|
||||
feature_category :error_tracking
|
||||
urgency :low
|
||||
|
||||
params do
|
||||
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
|
||||
requires :id, types: [String, Integer],
|
||||
desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
|
||||
end
|
||||
|
||||
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
|
|
@ -17,9 +20,11 @@ module API
|
|||
authorize! :admin_operations, user_project
|
||||
end
|
||||
|
||||
desc 'List all client keys' do
|
||||
detail 'This feature was introduced in GitLab 14.3.'
|
||||
desc 'List project client keys' do
|
||||
detail 'List all client keys. This feature was introduced in GitLab 14.3.'
|
||||
success Entities::ErrorTracking::ClientKey
|
||||
is_array true
|
||||
tags ERROR_TRACKING_CLIENT_KEYS_TAGS
|
||||
end
|
||||
get '/client_keys' do
|
||||
collection = user_project.error_tracking_client_keys
|
||||
|
|
@ -28,8 +33,10 @@ module API
|
|||
end
|
||||
|
||||
desc 'Create a client key' do
|
||||
detail 'This feature was introduced in GitLab 14.3.'
|
||||
detail 'Creates a new client key for a project. The public key attribute is generated automatically.'\
|
||||
'This feature was introduced in GitLab 14.3.'
|
||||
success Entities::ErrorTracking::ClientKey
|
||||
tags ERROR_TRACKING_CLIENT_KEYS_TAGS
|
||||
end
|
||||
post '/client_keys' do
|
||||
key = user_project.error_tracking_client_keys.create!
|
||||
|
|
@ -38,8 +45,14 @@ module API
|
|||
end
|
||||
|
||||
desc 'Delete a client key' do
|
||||
detail 'This feature was introduced in GitLab 14.3.'
|
||||
detail 'Removes a client key from the project. This feature was introduced in GitLab 14.3.'
|
||||
success Entities::ErrorTracking::ClientKey
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags ERROR_TRACKING_CLIENT_KEYS_TAGS
|
||||
end
|
||||
delete '/client_keys/:key_id' do
|
||||
key = user_project.error_tracking_client_keys.find(params[:key_id])
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ module API
|
|||
helpers Gitlab::Golang
|
||||
helpers ::API::Helpers::PackagesHelpers
|
||||
|
||||
GO_PROXY_TAGS = %w[go_proxy].freeze
|
||||
|
||||
feature_category :package_registry
|
||||
urgency :low
|
||||
|
||||
|
|
@ -62,18 +64,21 @@ module API
|
|||
end
|
||||
|
||||
params do
|
||||
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
|
||||
requires :module_name, type: String, desc: 'Module name', coerce_with: ->(val) { CGI.unescape(val) }
|
||||
requires :id, types: [String, Integer], desc: 'The project ID or full path of a project'
|
||||
requires :module_name, type: String, desc: 'The name of the Go module', coerce_with: ->(val) { CGI.unescape(val) }
|
||||
end
|
||||
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, authenticate_non_public: true
|
||||
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true,
|
||||
authenticate_non_public: true
|
||||
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
before do
|
||||
authorize_read_package!(project)
|
||||
end
|
||||
|
||||
namespace ':id/packages/go/*module_name/@v' do
|
||||
desc 'Get all tagged versions for a given Go module' do
|
||||
detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/list. This feature was introduced in GitLab 13.1.'
|
||||
desc 'List' do
|
||||
detail 'Get all tagged versions for a given Go module.'\
|
||||
'See `go help goproxy`, GET $GOPROXY/<module>/@v/list. This feature was introduced in GitLab 13.1.'
|
||||
tags GO_PROXY_TAGS
|
||||
end
|
||||
get 'list' do
|
||||
mod = find_module
|
||||
|
|
@ -82,12 +87,14 @@ module API
|
|||
mod.versions.map { |t| t.name }.join("\n")
|
||||
end
|
||||
|
||||
desc 'Get information about the given module version' do
|
||||
detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.info. This feature was introduced in GitLab 13.1.'
|
||||
desc 'Version metadata' do
|
||||
detail 'Get all tagged versions for a given Go module.'\
|
||||
'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.info. This feature was introduced in GitLab 13.1'
|
||||
success ::API::Entities::GoModuleVersion
|
||||
tags GO_PROXY_TAGS
|
||||
end
|
||||
params do
|
||||
requires :module_version, type: String, desc: 'Module version'
|
||||
requires :module_version, type: String, desc: 'The version of the Go module'
|
||||
end
|
||||
get ':module_version.info', requirements: MODULE_VERSION_REQUIREMENTS do
|
||||
ver = find_version
|
||||
|
|
@ -95,11 +102,13 @@ module API
|
|||
present ::Packages::Go::ModuleVersionPresenter.new(ver), with: ::API::Entities::GoModuleVersion
|
||||
end
|
||||
|
||||
desc 'Get the module file of the given module version' do
|
||||
detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.mod. This feature was introduced in GitLab 13.1.'
|
||||
desc 'Download module file' do
|
||||
detail 'Get the module file of a given module version.'\
|
||||
'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.mod. This feature was introduced in GitLab 13.1.'
|
||||
tags GO_PROXY_TAGS
|
||||
end
|
||||
params do
|
||||
requires :module_version, type: String, desc: 'Module version'
|
||||
requires :module_version, type: String, desc: 'The version of the Go module'
|
||||
end
|
||||
get ':module_version.mod', requirements: MODULE_VERSION_REQUIREMENTS do
|
||||
ver = find_version
|
||||
|
|
@ -108,18 +117,21 @@ module API
|
|||
ver.gomod
|
||||
end
|
||||
|
||||
desc 'Get a zip of the source of the given module version' do
|
||||
detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.zip. This feature was introduced in GitLab 13.1.'
|
||||
desc 'Download module source' do
|
||||
detail 'Get a zip of the source of the given module version.'\
|
||||
'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.zip. This feature was introduced in GitLab 13.1.'
|
||||
tags GO_PROXY_TAGS
|
||||
end
|
||||
params do
|
||||
requires :module_version, type: String, desc: 'Module version'
|
||||
requires :module_version, type: String, desc: 'The version of the Go module'
|
||||
end
|
||||
get ':module_version.zip', requirements: MODULE_VERSION_REQUIREMENTS do
|
||||
ver = find_version
|
||||
|
||||
content_type 'application/zip'
|
||||
env['api.format'] = :binary
|
||||
header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: ver.name + '.zip')
|
||||
header['Content-Disposition'] =
|
||||
ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: "#{ver.name}.zip")
|
||||
header['Content-Transfer-Encoding'] = 'binary'
|
||||
status :ok
|
||||
body ver.archive.string
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def blobs(limit: count_limit)
|
||||
return [] unless Ability.allowed?(@current_user, :download_code, @project)
|
||||
return [] unless Ability.allowed?(@current_user, :read_code, @project)
|
||||
|
||||
@blobs ||= Gitlab::FileFinder.new(project, repository_project_ref).find(query, content_match_cutoff: limit)
|
||||
end
|
||||
|
|
@ -153,7 +153,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def find_commits(query, limit:)
|
||||
return [] unless Ability.allowed?(@current_user, :download_code, @project)
|
||||
return [] unless Ability.allowed?(@current_user, :read_code, @project)
|
||||
|
||||
commits = find_commits_by_message(query, limit: limit)
|
||||
commit_by_sha = find_commit_by_sha(query)
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ module Gitlab
|
|||
parse_params do |raw_duration|
|
||||
Gitlab::TimeTrackingFormatter.parse(raw_duration)
|
||||
end
|
||||
command :estimate do |time_estimate|
|
||||
command :estimate, :estimate_time do |time_estimate|
|
||||
if time_estimate
|
||||
@updates[:time_estimate] = time_estimate
|
||||
end
|
||||
|
|
@ -184,7 +184,7 @@ module Gitlab
|
|||
parse_params do |raw_time_date|
|
||||
Gitlab::QuickActions::SpendTimeAndDateSeparator.new(raw_time_date).execute
|
||||
end
|
||||
command :spend, :spent do |time_spent, time_spent_date|
|
||||
command :spend, :spent, :spend_time do |time_spent, time_spent_date|
|
||||
if time_spent
|
||||
@updates[:spend_time] = {
|
||||
duration: time_spent,
|
||||
|
|
@ -202,7 +202,7 @@ module Gitlab
|
|||
quick_action_target.persisted? &&
|
||||
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
|
||||
end
|
||||
command :remove_estimate do
|
||||
command :remove_estimate, :remove_time_estimate do
|
||||
@updates[:time_estimate] = 0
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,9 @@ namespace :tw do
|
|||
CodeOwnerRule.new('Workspace', '@lciutacu')
|
||||
].freeze
|
||||
|
||||
CODEOWNERS_BLOCK_BEGIN = "# Begin rake-managed-docs-block"
|
||||
CODEOWNERS_BLOCK_END = "# End rake-managed-docs-block"
|
||||
|
||||
Document = Struct.new(:group, :redirect) do
|
||||
def has_a_valid_group?
|
||||
group && !redirect
|
||||
|
|
@ -124,7 +127,17 @@ namespace :tw do
|
|||
end
|
||||
end
|
||||
|
||||
deduplicated_mappings.sort.each { |mapping| puts mapping }
|
||||
new_docs_owners = deduplicated_mappings.sort.join("\n")
|
||||
|
||||
codeowners_path = Rails.root.join('.gitlab/CODEOWNERS')
|
||||
current_codeowners_content = File.read(codeowners_path)
|
||||
|
||||
docs_replace_regex = Regexp.new("#{CODEOWNERS_BLOCK_BEGIN}\n[\\s\\S]*?\n#{CODEOWNERS_BLOCK_END}")
|
||||
|
||||
new_codeowners_content = current_codeowners_content
|
||||
.gsub(docs_replace_regex, "#{CODEOWNERS_BLOCK_BEGIN}\n#{new_docs_owners}\n#{CODEOWNERS_BLOCK_END}")
|
||||
|
||||
File.write(codeowners_path, new_codeowners_content)
|
||||
|
||||
if errors.present?
|
||||
puts "-----"
|
||||
|
|
|
|||
|
|
@ -46510,10 +46510,10 @@ msgstr ""
|
|||
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
|
||||
msgstr ""
|
||||
|
||||
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
|
||||
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "You can %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
|
||||
msgid "You can %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "You can adjust rules on auto-banning %{link_start}here%{link_end}."
|
||||
|
|
|
|||
|
|
@ -80,11 +80,13 @@ class CreatePipelineFailureIncident
|
|||
|
||||
If you believe that there's an easy resolution by either:
|
||||
|
||||
- Reverting a particular merge request. Make sure to add the ~"pipeline:revert" label in that case, to speed up the revert pipeline.
|
||||
- Reverting a particular merge request.
|
||||
- Making a quick fix (for example, one line or a few similar simple changes in a few lines).
|
||||
You can create a merge request, assign to any available maintainer, and ping people that were involved/related to the introduction of the failure.
|
||||
Additionally, a message can be posted in `#backend_maintainers` or `#frontend_maintainers` to get a maintainer take a look at the fix ASAP.
|
||||
|
||||
In both cases, make sure to add the ~"pipeline:expedite-master-fixing" label, and `master:broken` or `master:foss-broken` label, to speed up the `master`-fixing pipelines.
|
||||
|
||||
### Resolution
|
||||
|
||||
Follow [the Resolution steps from the handbook](https://about.gitlab.com/handbook/engineering/workflow/#responsibilities-of-the-resolution-dri).
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ puts
|
|||
|
||||
if additional_flags.count > 0
|
||||
puts "==================================================".green.bold
|
||||
puts "There are feature flags that appears to be unknown".yellow
|
||||
puts "There are feature flags that appear to be unknown".yellow
|
||||
puts
|
||||
puts "They appear to be used by CI, but we do lack their YAML definition".yellow
|
||||
puts "This is likely expected, so feel free to ignore that list:".yellow
|
||||
|
|
@ -110,7 +110,7 @@ end
|
|||
|
||||
if unused_flags.count > 0
|
||||
puts "========================================".green.bold
|
||||
puts "These feature flags appears to be UNUSED".red.bold
|
||||
puts "These feature flags appear to be UNUSED".red.bold
|
||||
puts
|
||||
puts "If they are really no longer needed REMOVE their .yml definition".red
|
||||
puts "If they are needed you need to ENSURE that their usage is covered with specs to continue.".red
|
||||
|
|
|
|||
|
|
@ -0,0 +1,222 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Merge request > User sees discussions navigation', :js do
|
||||
let_it_be(:project) { create(:project, :public, :repository) }
|
||||
let_it_be(:user) { project.creator }
|
||||
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
before do
|
||||
# FIXME: before removing this please fix discussions navigation with this flag enabled
|
||||
stub_feature_flags(moved_mr_sidebar: false)
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
describe 'Code discussions' do
|
||||
let!(:position) do
|
||||
build(:text_diff_position, :added,
|
||||
file: "files/images/wm.svg",
|
||||
new_line: 1,
|
||||
diff_refs: merge_request.diff_refs
|
||||
)
|
||||
end
|
||||
|
||||
let!(:first_discussion) do
|
||||
create(:diff_note_on_merge_request,
|
||||
noteable: merge_request,
|
||||
project: project,
|
||||
position: position
|
||||
).to_discussion
|
||||
end
|
||||
|
||||
let!(:second_discussion) do
|
||||
create(:diff_note_on_merge_request,
|
||||
noteable: merge_request,
|
||||
project: project,
|
||||
position: position
|
||||
).to_discussion
|
||||
end
|
||||
|
||||
let(:first_discussion_selector) { ".discussion[data-discussion-id='#{first_discussion.id}']" }
|
||||
let(:second_discussion_selector) { ".discussion[data-discussion-id='#{second_discussion.id}']" }
|
||||
|
||||
shared_examples 'a page with a thread navigation' do
|
||||
context 'with active threads' do
|
||||
it 'navigates to the first thread' do
|
||||
goto_next_thread
|
||||
expect(page).to have_selector(first_discussion_selector, obscured: false)
|
||||
end
|
||||
|
||||
it 'navigates to the last thread' do
|
||||
goto_previous_thread
|
||||
expect(page).to have_selector(second_discussion_selector, obscured: false)
|
||||
end
|
||||
|
||||
it 'navigates through active threads' do
|
||||
goto_next_thread
|
||||
goto_next_thread
|
||||
expect(page).to have_selector(second_discussion_selector, obscured: false)
|
||||
end
|
||||
|
||||
it 'cycles back to the first thread' do
|
||||
goto_next_thread
|
||||
goto_next_thread
|
||||
goto_next_thread
|
||||
expect(page).to have_selector(first_discussion_selector, obscured: false)
|
||||
end
|
||||
|
||||
it 'cycles back to the last thread' do
|
||||
goto_previous_thread
|
||||
goto_previous_thread
|
||||
goto_previous_thread
|
||||
expect(page).to have_selector(second_discussion_selector, obscured: false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with resolved threads' do
|
||||
let!(:resolved_discussion) do
|
||||
create(:diff_note_on_merge_request,
|
||||
noteable: merge_request,
|
||||
project: project,
|
||||
position: position
|
||||
).to_discussion
|
||||
end
|
||||
|
||||
let(:resolved_discussion_selector) { ".discussion[data-discussion-id='#{resolved_discussion.id}']" }
|
||||
|
||||
before do
|
||||
# :resolved attr doesn't actually resolve the thread but just collapses it
|
||||
page.within(resolved_discussion_selector) do
|
||||
click_button text: 'Resolve thread'
|
||||
end
|
||||
page.execute_script("window.scrollTo(0,0)")
|
||||
end
|
||||
|
||||
it 'excludes resolved threads during navigation' do
|
||||
goto_next_thread
|
||||
goto_next_thread
|
||||
goto_next_thread
|
||||
expect(page).to have_selector(first_discussion_selector, obscured: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Overview page discussions navigation" do
|
||||
before do
|
||||
visit project_merge_request_path(project, merge_request)
|
||||
end
|
||||
|
||||
it_behaves_like 'a page with a thread navigation'
|
||||
|
||||
context 'with collapsed threads' do
|
||||
before do
|
||||
page.within(first_discussion_selector) do
|
||||
click_button 'Hide thread'
|
||||
end
|
||||
end
|
||||
|
||||
it 'expands threads during navigation' do
|
||||
goto_next_thread
|
||||
expect(page).to have_selector "#note_#{first_discussion.first_note.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Changes page discussions navigation" do
|
||||
before do
|
||||
visit diffs_project_merge_request_path(project, merge_request)
|
||||
end
|
||||
|
||||
it_behaves_like 'a page with a thread navigation'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Merge request discussions' do
|
||||
shared_examples 'a page with no code discussions' do
|
||||
let!(:first_discussion) do
|
||||
create(:discussion_note_on_merge_request,
|
||||
noteable: merge_request,
|
||||
project: project
|
||||
).to_discussion
|
||||
end
|
||||
|
||||
let!(:second_discussion) do
|
||||
create(:discussion_note_on_merge_request,
|
||||
noteable: merge_request,
|
||||
project: project
|
||||
).to_discussion
|
||||
end
|
||||
|
||||
let(:first_discussion_selector) { ".discussion[data-discussion-id='#{first_discussion.id}']" }
|
||||
let(:second_discussion_selector) { ".discussion[data-discussion-id='#{second_discussion.id}']" }
|
||||
|
||||
describe "Changes page discussions navigation" do
|
||||
it 'navigates to the first discussion on the Overview page' do
|
||||
goto_next_thread
|
||||
expect(page).to have_selector(first_discussion_selector, obscured: false)
|
||||
end
|
||||
|
||||
it 'navigates to the last discussion on the Overview page' do
|
||||
goto_previous_thread
|
||||
expect(page).to have_selector(second_discussion_selector, obscured: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'on changes page' do
|
||||
before do
|
||||
visit diffs_project_merge_request_path(project, merge_request)
|
||||
end
|
||||
|
||||
it_behaves_like 'a page with no code discussions'
|
||||
end
|
||||
|
||||
context 'on commits page' do
|
||||
before do
|
||||
# we can't go directly to the commits page since it doesn't load discussions
|
||||
visit project_merge_request_path(project, merge_request)
|
||||
click_link 'Commits'
|
||||
end
|
||||
|
||||
it_behaves_like 'a page with no code discussions'
|
||||
end
|
||||
|
||||
context 'on pipelines page' do
|
||||
before do
|
||||
visit project_merge_request_path(project, merge_request)
|
||||
click_link 'Pipelines'
|
||||
end
|
||||
|
||||
it_behaves_like 'a page with no code discussions'
|
||||
end
|
||||
end
|
||||
|
||||
def goto_next_thread
|
||||
begin
|
||||
# this is required when moved_mr_sidebar is enabled
|
||||
page.within('.issue-sticky-header') do
|
||||
click_button 'Go to next unresolved thread'
|
||||
end
|
||||
rescue StandardError
|
||||
click_button 'Go to next unresolved thread'
|
||||
end
|
||||
wait_for_scroll_end
|
||||
end
|
||||
|
||||
def goto_previous_thread
|
||||
begin
|
||||
page.within('.issue-sticky-header') do
|
||||
click_button 'Go to previous unresolved thread'
|
||||
end
|
||||
rescue StandardError
|
||||
click_button 'Go to previous unresolved thread'
|
||||
end
|
||||
wait_for_scroll_end
|
||||
end
|
||||
|
||||
def wait_for_scroll_end
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
|
|
@ -34,6 +34,23 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
added_lines: 0,
|
||||
file_hash: 'test',
|
||||
},
|
||||
{
|
||||
new_path: 'constructor/test/aFile.js',
|
||||
deleted_file: false,
|
||||
new_file: true,
|
||||
removed_lines: 0,
|
||||
added_lines: 42,
|
||||
file_hash: 'test',
|
||||
},
|
||||
{
|
||||
new_path: 'submodule @ abcdef123',
|
||||
deleted_file: false,
|
||||
new_file: true,
|
||||
removed_lines: 0,
|
||||
added_lines: 1,
|
||||
submodule: true,
|
||||
file_hash: 'test',
|
||||
},
|
||||
{
|
||||
new_path: 'package.json',
|
||||
deleted_file: true,
|
||||
|
|
@ -66,6 +83,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
path: 'app/index.js',
|
||||
removedLines: 10,
|
||||
tempFile: false,
|
||||
submodule: undefined,
|
||||
type: 'blob',
|
||||
tree: [],
|
||||
},
|
||||
|
|
@ -87,6 +105,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
path: 'app/test/index.js',
|
||||
removedLines: 0,
|
||||
tempFile: true,
|
||||
submodule: undefined,
|
||||
type: 'blob',
|
||||
tree: [],
|
||||
},
|
||||
|
|
@ -101,6 +120,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
path: 'app/test/filepathneedstruncating.js',
|
||||
removedLines: 0,
|
||||
tempFile: true,
|
||||
submodule: undefined,
|
||||
type: 'blob',
|
||||
tree: [],
|
||||
},
|
||||
|
|
@ -109,6 +129,45 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
],
|
||||
opened: true,
|
||||
},
|
||||
{
|
||||
key: 'constructor',
|
||||
name: 'constructor/test',
|
||||
opened: true,
|
||||
path: 'constructor',
|
||||
tree: [
|
||||
{
|
||||
addedLines: 42,
|
||||
changed: true,
|
||||
deleted: false,
|
||||
fileHash: 'test',
|
||||
key: 'constructor/test/aFile.js',
|
||||
name: 'aFile.js',
|
||||
parentPath: 'constructor/test/',
|
||||
path: 'constructor/test/aFile.js',
|
||||
removedLines: 0,
|
||||
submodule: undefined,
|
||||
tempFile: true,
|
||||
tree: [],
|
||||
type: 'blob',
|
||||
},
|
||||
],
|
||||
type: 'tree',
|
||||
},
|
||||
{
|
||||
key: 'submodule @ abcdef123',
|
||||
parentPath: '/',
|
||||
path: 'submodule @ abcdef123',
|
||||
name: 'submodule @ abcdef123',
|
||||
type: 'blob',
|
||||
changed: true,
|
||||
tempFile: true,
|
||||
submodule: true,
|
||||
deleted: false,
|
||||
fileHash: 'test',
|
||||
addedLines: 1,
|
||||
removedLines: 0,
|
||||
tree: [],
|
||||
},
|
||||
{
|
||||
key: 'package.json',
|
||||
parentPath: '/',
|
||||
|
|
@ -117,6 +176,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
type: 'blob',
|
||||
changed: true,
|
||||
tempFile: false,
|
||||
submodule: undefined,
|
||||
deleted: true,
|
||||
fileHash: 'test',
|
||||
addedLines: 0,
|
||||
|
|
@ -135,6 +195,10 @@ describe('~/diffs/utils/tree_worker_utils', () => {
|
|||
'app/test',
|
||||
'app/test/index.js',
|
||||
'app/test/filepathneedstruncating.js',
|
||||
'constructor',
|
||||
'constructor/test',
|
||||
'constructor/test/aFile.js',
|
||||
'submodule @ abcdef123',
|
||||
'package.json',
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ RSpec.describe SearchHelper do
|
|||
expect(search_autocomplete_opts("Network").size).to eq(1)
|
||||
expect(search_autocomplete_opts("Graph").size).to eq(1)
|
||||
|
||||
allow(self).to receive(:can?).with(user, :download_code, @project).and_return(false)
|
||||
allow(self).to receive(:can?).with(user, :read_code, @project).and_return(false)
|
||||
|
||||
expect(search_autocomplete_opts("Files").size).to eq(0)
|
||||
expect(search_autocomplete_opts("Commits").size).to eq(0)
|
||||
|
|
|
|||
|
|
@ -103,13 +103,17 @@ RSpec.describe SearchController, type: :request do
|
|||
expect(response).not_to redirect_to(project_commit_path(project, sha))
|
||||
end
|
||||
|
||||
it 'does not redirect if user cannot download_code from project' do
|
||||
allow(Ability).to receive(:allowed?).and_call_original
|
||||
allow(Ability).to receive(:allowed?).with(user, :download_code, project).and_return(false)
|
||||
context 'when user cannot read_code' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).and_call_original
|
||||
allow(Ability).to receive(:allowed?).with(user, :read_code, project).and_return(false)
|
||||
end
|
||||
|
||||
send_search_request({ search: sha, project_id: project.id })
|
||||
it 'does not redirect' do
|
||||
send_search_request({ search: sha, project_id: project.id })
|
||||
|
||||
expect(response).not_to redirect_to(project_commit_path(project, sha))
|
||||
expect(response).not_to redirect_to(project_commit_path(project, sha))
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not redirect if commit sha not found in project' do
|
||||
|
|
|
|||
|
|
@ -1450,6 +1450,11 @@ RSpec.describe QuickActions::InterpretService do
|
|||
let(:issuable) { issue }
|
||||
end
|
||||
|
||||
it_behaves_like 'estimate command' do
|
||||
let(:content) { '/estimate_time 1h' }
|
||||
let(:issuable) { issue }
|
||||
end
|
||||
|
||||
it_behaves_like 'failed command' do
|
||||
let(:content) { '/estimate' }
|
||||
let(:issuable) { issue }
|
||||
|
|
@ -1470,6 +1475,11 @@ RSpec.describe QuickActions::InterpretService do
|
|||
let(:issuable) { issue }
|
||||
end
|
||||
|
||||
it_behaves_like 'spend command' do
|
||||
let(:content) { '/spend_time 1h' }
|
||||
let(:issuable) { issue }
|
||||
end
|
||||
|
||||
it_behaves_like 'spend command with negative time' do
|
||||
let(:content) { '/spend -120m' }
|
||||
let(:issuable) { issue }
|
||||
|
|
@ -1537,6 +1547,11 @@ RSpec.describe QuickActions::InterpretService do
|
|||
let(:issuable) { issue }
|
||||
end
|
||||
|
||||
it_behaves_like 'remove_estimate command' do
|
||||
let(:content) { '/remove_time_estimate' }
|
||||
let(:issuable) { issue }
|
||||
end
|
||||
|
||||
it_behaves_like 'remove_time_spent command' do
|
||||
let(:content) { '/remove_time_spent' }
|
||||
let(:issuable) { issue }
|
||||
|
|
|
|||
Loading…
Reference in New Issue