Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-12-10 00:13:05 +00:00
parent 85e524e496
commit 1b47b087e6
62 changed files with 1366 additions and 386 deletions

View File

@ -118,7 +118,10 @@ export default class ShortcutsIssuable extends Shortcuts {
// Wait for the sidebar to trigger('click') open
// so it doesn't cause our dropdown to close preemptively
setTimeout(() => {
document.querySelector(`.block.${name} .shortcut-sidebar-dropdown-toggle`).click();
const editBtn =
document.querySelector(`.block.${name} .shortcut-sidebar-dropdown-toggle`) ||
document.querySelector(`.block.${name} .edit-link`);
editBtn.click();
}, DEBOUNCE_DROPDOWN_DELAY);
return false;
}

View File

@ -6,9 +6,9 @@ import initFilePickers from '~/file_pickers';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
import initProjectDeleteButton from '~/projects/project_delete_button';
import initServiceDesk from '~/projects/settings_service_desk';
import initTransferProjectForm from '~/projects/settings/init_transfer_project_form';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
import setupTransferEdit from '~/transfer_edit';
import UserCallout from '~/user_callout';
import initTopicsTokenSelector from '~/projects/settings/topics';
import initProjectPermissionsSettings from '../shared/permissions';
@ -26,7 +26,7 @@ initServiceDesk();
initProjectLoadingSpinner();
initProjectPermissionsSettings();
setupTransferEdit('.js-project-transfer-form', 'select.select2');
initTransferProjectForm();
dirtySubmitFactory(document.querySelectorAll('.js-general-settings-form, .js-mr-settings-form'));

View File

@ -0,0 +1,63 @@
<script>
import { GlFormGroup } from '@gitlab/ui';
import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select.vue';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
export default {
name: 'TransferProjectForm',
components: {
GlFormGroup,
NamespaceSelect,
ConfirmDanger,
},
props: {
namespaces: {
type: Object,
required: true,
},
confirmationPhrase: {
type: String,
required: true,
},
confirmButtonText: {
type: String,
required: true,
},
},
data() {
return { selectedNamespace: null };
},
computed: {
hasSelectedNamespace() {
return Boolean(this.selectedNamespace?.id);
},
},
methods: {
handleSelect(selectedNamespace) {
this.selectedNamespace = selectedNamespace;
this.$emit('selectNamespace', selectedNamespace.id);
},
},
};
</script>
<template>
<div>
<gl-form-group>
<namespace-select
class="qa-namespaces-list"
data-testid="transfer-project-namespace"
:full-width="true"
:data="namespaces"
:selected-namespace="selectedNamespace"
@select="handleSelect"
/>
</gl-form-group>
<confirm-danger
button-class="qa-transfer-button"
:disabled="!hasSelectedNamespace"
:phrase="confirmationPhrase"
:button-text="confirmButtonText"
@confirm="$emit('confirm')"
/>
</div>
</template>

View File

@ -0,0 +1,53 @@
import Vue from 'vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import TransferProjectForm from './components/transfer_project_form.vue';
const prepareNamespaces = (rawNamespaces = '') => {
const data = JSON.parse(rawNamespaces);
return {
group: data?.group.map(convertObjectPropsToCamelCase),
user: data?.user.map(convertObjectPropsToCamelCase),
};
};
export default () => {
const el = document.querySelector('.js-transfer-project-form');
if (!el) {
return false;
}
const {
targetFormId = null,
targetHiddenInputId = null,
buttonText: confirmButtonText = '',
phrase: confirmationPhrase = '',
confirmDangerMessage = '',
namespaces = '',
} = el.dataset;
return new Vue({
el,
provide: {
confirmDangerMessage,
},
render(createElement) {
return createElement(TransferProjectForm, {
props: {
confirmButtonText,
confirmationPhrase,
namespaces: prepareNamespaces(namespaces),
},
on: {
selectNamespace: (id) => {
if (targetHiddenInputId && document.getElementById(targetHiddenInputId)) {
document.getElementById(targetHiddenInputId).value = id;
}
},
confirm: () => {
if (targetFormId) document.getElementById(targetFormId)?.submit();
},
},
});
},
});
};

View File

@ -47,7 +47,7 @@ export default {
actionPrimary() {
return {
text: this.confirmButtonText,
attributes: [{ variant: 'danger', disabled: !this.isValid }],
attributes: [{ variant: 'danger', disabled: !this.isValid, class: 'qa-confirm-button' }],
};
},
},
@ -95,7 +95,7 @@ export default {
<gl-form-input
id="confirm_name_input"
v-model="confirmationPhrase"
class="form-control"
class="form-control qa-confirm-input"
data-testid="confirm-danger-input"
type="text"
/>

View File

@ -0,0 +1,93 @@
<script>
import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader, GlSearchBoxByType } from '@gitlab/ui';
import { __ } from '~/locale';
export const i18n = {
DEFAULT_TEXT: __('Select a new namespace'),
GROUPS: __('Groups'),
USERS: __('Users'),
};
const filterByName = (data, searchTerm = '') =>
data.filter((d) => d.humanName.toLowerCase().includes(searchTerm));
export default {
name: 'NamespaceSelect',
components: {
GlDropdown,
GlDropdownItem,
GlDropdownSectionHeader,
GlSearchBoxByType,
},
props: {
data: {
type: Object,
required: true,
},
fullWidth: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
searchTerm: '',
selectedNamespace: null,
};
},
computed: {
hasUserNamespaces() {
return this.data.user?.length;
},
hasGroupNamespaces() {
return this.data.group?.length;
},
filteredGroupNamespaces() {
if (!this.hasGroupNamespaces) return [];
return filterByName(this.data.group, this.searchTerm);
},
filteredUserNamespaces() {
if (!this.hasUserNamespaces) return [];
return filterByName(this.data.user, this.searchTerm);
},
selectedNamespaceText() {
return this.selectedNamespace?.humanName || this.$options.i18n.DEFAULT_TEXT;
},
},
methods: {
handleSelect(item) {
this.selectedNamespace = item;
this.$emit('select', item);
},
},
i18n,
};
</script>
<template>
<gl-dropdown :text="selectedNamespaceText" :block="fullWidth">
<template #header>
<gl-search-box-by-type v-model.trim="searchTerm" />
</template>
<div v-if="hasGroupNamespaces" class="qa-namespaces-list-groups">
<gl-dropdown-section-header>{{ $options.i18n.GROUPS }}</gl-dropdown-section-header>
<gl-dropdown-item
v-for="item in filteredGroupNamespaces"
:key="item.id"
class="qa-namespaces-list-item"
@click="handleSelect(item)"
>{{ item.humanName }}</gl-dropdown-item
>
</div>
<div v-if="hasUserNamespaces" class="qa-namespaces-list-users">
<gl-dropdown-section-header>{{ $options.i18n.USERS }}</gl-dropdown-section-header>
<gl-dropdown-item
v-for="item in filteredUserNamespaces"
:key="item.id"
class="qa-namespaces-list-item"
@click="handleSelect(item)"
>{{ item.humanName }}</gl-dropdown-item
>
</div>
</gl-dropdown>
</template>

View File

@ -119,7 +119,10 @@ class ProjectsController < Projects::ApplicationController
if @project.errors[:new_namespace].present?
flash[:alert] = @project.errors[:new_namespace].first
return redirect_to edit_project_path(@project)
end
render_edit
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -76,7 +76,10 @@ module Repositories
existing_oids = project.lfs_objects_oids(oids: objects_oids)
objects.each do |object|
object[:actions] = upload_actions(object) unless existing_oids.include?(object[:oid])
next if existing_oids.include?(object[:oid])
next if should_auto_link? && oids_from_fork.include?(object[:oid]) && link_to_project!(object)
object[:actions] = upload_actions(object)
end
objects
@ -150,6 +153,26 @@ module Repositories
Gitlab::LfsToken.new(user).basic_encoding
end
def should_auto_link?
return false unless Feature.enabled?(:lfs_auto_link_fork_source, project)
return false unless project.forked?
# Sanity check in case for some reason the user doesn't have access to the parent
can?(user, :download_code, project.fork_source)
end
def oids_from_fork
@oids_from_fork ||= project.lfs_objects_oids_from_fork_source(oids: objects_oids)
end
def link_to_project!(object)
lfs_object = LfsObject.for_oid_and_size(object[:oid], object[:size])
return unless lfs_object
LfsObjectsProject.link_to_project!(lfs_object, project)
end
end
end

View File

@ -88,6 +88,13 @@ module NamespacesHelper
group.namespace_settings.public_send(method_name, **args) # rubocop:disable GitlabSecurity/PublicSend
end
def namespaces_as_json(selected = :current_user)
{
group: formatted_namespaces(current_user.manageable_groups_with_routes),
user: formatted_namespaces([current_user.namespace])
}.to_json
end
private
# Many importers create a temporary Group, so use the real
@ -119,6 +126,17 @@ module NamespacesHelper
[group_label.camelize, elements]
end
def formatted_namespaces(namespaces)
namespaces.sort_by(&:human_name).map! do |n|
{
id: n.id,
display_path: n.full_path,
human_name: n.human_name,
name: n.name
}
end
end
end
NamespacesHelper.prepend_mod_with('NamespacesHelper')

View File

@ -13,6 +13,7 @@ class LfsObject < ApplicationRecord
scope :with_files_stored_locally, -> { where(file_store: LfsObjectUploader::Store::LOCAL) }
scope :with_files_stored_remotely, -> { where(file_store: LfsObjectUploader::Store::REMOTE) }
scope :for_oids, -> (oids) { where(oid: oids) }
scope :for_oid_and_size, -> (oid, size) { find_by(oid: oid, size: size) }
validates :oid, presence: true, uniqueness: true

View File

@ -21,9 +21,19 @@ class LfsObjectsProject < ApplicationRecord
scope :project_id_in, ->(ids) { where(project_id: ids) }
scope :lfs_object_in, -> (lfs_objects) { where(lfs_object: lfs_objects) }
def self.link_to_project!(lfs_object, project)
# We can't use an upsert here because there is no uniqueness constraint:
# https://gitlab.com/gitlab-org/gitlab/-/issues/347466
self.safe_find_or_create_by!(lfs_object_id: lfs_object.id, project_id: project.id) # rubocop:disable Performance/ActiveRecordSubtransactionMethods
end
def self.update_statistics_for_project_id(project_id)
ProjectCacheWorker.perform_async(project_id, [], [:lfs_objects_size]) # rubocop:disable CodeReuse/Worker
end
private
def update_project_statistics
ProjectCacheWorker.perform_async(project_id, [], [:lfs_objects_size])
self.class.update_statistics_for_project_id(project_id)
end
end

View File

@ -1569,6 +1569,12 @@ class Project < ApplicationRecord
oids(lfs_objects, oids: oids)
end
def lfs_objects_oids_from_fork_source(oids: [])
return [] unless forked?
oids(fork_source.lfs_objects, oids: oids)
end
def personal?
!group
end

View File

@ -8,7 +8,7 @@ module Groups
validate_params
update_shared_runners
update_pending_builds!
update_pending_builds_async
success
@ -28,12 +28,18 @@ module Groups
group.update_shared_runners_setting!(params[:shared_runners_setting])
end
def update_pending_builds!
return unless group.previous_changes.include?('shared_runners_enabled')
def update_pending_builds?
group.previous_changes.include?('shared_runners_enabled')
end
update_params = { instance_runners_enabled: group.shared_runners_enabled }
def update_pending_builds_async
return unless update_pending_builds?
::Ci::UpdatePendingBuildService.new(group, update_params).execute
group.run_after_commit_or_now do |group|
pending_builds_params = { instance_runners_enabled: group.shared_runners_enabled }
::Ci::UpdatePendingBuildService.new(group, pending_builds_params).execute
end
end
end
end

View File

@ -1,8 +1,11 @@
- return unless can?(current_user, :change_namespace, @project)
- form_id = "transfer-project-form"
- hidden_input_id = "new_namespace_id"
- initial_data = { namespaces: namespaces_as_json, button_text: s_('ProjectSettings|Transfer project'), confirm_danger_message: transfer_project_message(@project), phrase: @project.name, target_form_id: form_id, target_hidden_input_id: hidden_input_id }
.sub-section
%h4.danger-title= _('Transfer project')
= form_for @project, url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'js-project-transfer-form' } do |f|
= form_for @project, url: transfer_project_path(@project), method: :put, html: { class: 'js-project-transfer-form', id: form_id } do |f|
.form-group
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/index', anchor: 'transferring-an-existing-project-into-another-namespace') }
%p= _("Transfer your project into another namespace. %{link_start}Learn more.%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
@ -11,7 +14,6 @@
%li= _('You can only transfer the project to namespaces you manage.')
%li= _('You will need to update your local repositories to point to the new location.')
%li= _('Project visibility level will be changed to match namespace rules when transferring to a group.')
= hidden_field_tag(hidden_input_id)
= label_tag :new_namespace_id, _('Select a new namespace'), class: 'gl-font-weight-bold'
.form-group
= select_tag :new_namespace_id, namespaces_options(nil), include_blank: true, class: 'select2'
= f.submit 'Transfer project', class: "gl-button btn btn-danger js-legacy-confirm-danger qa-transfer-button", data: { "confirm-danger-message" => transfer_project_message(@project) }
.js-transfer-project-form{ data: initial_data }

View File

@ -1,2 +0,0 @@
:plain
location.href = "#{edit_project_path(@project)}";

View File

@ -0,0 +1,8 @@
---
name: lfs_auto_link_fork_source
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75972
rollout_issue_url:
milestone: '14.6'
type: development
group: group::source code
default_enabled: false

View File

@ -49,6 +49,7 @@ options:
- p_ci_templates_security_api_fuzzing_latest
- p_ci_templates_security_secure_binaries
- p_ci_templates_security_dast_api
- p_ci_templates_security_dast_api_latest
- p_ci_templates_security_container_scanning
- p_ci_templates_security_dast_latest
- p_ci_templates_security_dependency_scanning
@ -153,6 +154,7 @@ options:
- p_ci_templates_implicit_security_api_fuzzing_latest
- p_ci_templates_implicit_security_secure_binaries
- p_ci_templates_implicit_security_dast_api
- p_ci_templates_implicit_security_dast_api_latest
- p_ci_templates_implicit_security_container_scanning
- p_ci_templates_implicit_security_dast_latest
- p_ci_templates_implicit_security_dependency_scanning

View File

@ -0,0 +1,25 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_dast_api_latest_monthly
description: Monthly counts for DAST API latest CI template
product_section: sec
product_stage: secure
product_group: dynamic_analysis
product_category: dynamic_application_security_testing
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73876
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_implicit_security_dast_api_latest

View File

@ -0,0 +1,25 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_security_dast_api_latest_monthly
description: Monthly counts for DAST API latest CI template
product_section: sec
product_stage: secure
product_group: dynamic_analysis
product_category: dynamic_application_security_testing
value_type: number
status: active
milestone: "14.6"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73876
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_security_dast_api_latest

View File

@ -49,6 +49,7 @@ options:
- p_ci_templates_security_api_fuzzing_latest
- p_ci_templates_security_secure_binaries
- p_ci_templates_security_dast_api
- p_ci_templates_security_dast_api_latest
- p_ci_templates_security_container_scanning
- p_ci_templates_security_dast_latest
- p_ci_templates_security_dependency_scanning
@ -153,6 +154,7 @@ options:
- p_ci_templates_implicit_security_api_fuzzing_latest
- p_ci_templates_implicit_security_secure_binaries
- p_ci_templates_implicit_security_dast_api
- p_ci_templates_implicit_security_dast_api_latest
- p_ci_templates_implicit_security_container_scanning
- p_ci_templates_implicit_security_dast_latest
- p_ci_templates_implicit_security_dependency_scanning

View File

@ -0,0 +1,25 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_dast_api_latest_weekly
description: Weekly counts for DAST API latest CI template
product_section: sec
product_stage: secure
product_group: dynamic_analysis
product_category: dynamic_application_security_testing
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73876
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_implicit_security_dast_api_latest

View File

@ -0,0 +1,25 @@
---
key_path: redis_hll_counters.ci_templates.p_ci_templates_security_dast_api_latest_weekly
description: Weekly counts for DAST API latest CI template
product_section: sec
product_stage: secure
product_group: dynamic_analysis
product_category: dynamic_application_security_testing
value_type: number
status: active
milestone: "14.6"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73876
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
options:
events:
- p_ci_templates_security_dast_api_latest

View File

@ -0,0 +1,16 @@
- name: "Deprecation of bundler-audit Dependency Scanning tool" # The name of the feature to be deprecated
announcement_milestone: "14.6" # The milestone when this feature was first announced as deprecated.
announcement_date: "2021-12-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
removal_milestone: "15.0" # The milestone when this feature is planned to be removed
body: | # Do not modify this line, instead modify the lines below.
As of 14.6 bundler-audit is being deprecated from Dependency Scanning. It will continue to be in our CI/CD template while deprecated. We are removing bundler-audit from Dependency Scanning on May 22, 2022 in 15.0. After this removal Ruby scanning functionality will not be affected as it is still being covered by Gemnasium.
If you have explicitly excluded bundler-audit using DS_EXCLUDED_ANALYZERS you will need to clean up (remove the reference) in 15.0. If you have customized your pipeline's Dependency Scanning configuration, for example to edit the `bundler-audit-dependency_scanning` job, you will want to switch to gemnasium-dependency_scanning before removal in 15.0, to prevent your pipeline from failing. If you have not used the DS_EXCLUDED_ANALYZERS to reference bundler-audit, or customized your template specifically for bundler-audit, you will not need to take action.
# The following items are not published on the docs page, but may be used in the future.
stage: secure # (optional - may be required in the future) String value of the stage that the feature was created in. e.g., Growth
tiers: ultimate # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/289832 # (optional) This is a link to the deprecation issue in GitLab
documentation_url: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/analyzers.html # (optional) This is a link to the current documentation page
image_url: # (optional) This is a link to a thumbnail image depicting the feature
video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
removal_date: 2022-05-22 # (optional - may be required in the future) YYYY-MM-DD format. This should almost always be the 22nd of a month (YYYY-MM-22), the date of the milestone release when this feature is planned to be removed

View File

@ -9,8 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab offers a way to view the changes made within the GitLab server for owners and administrators
on a [paid plan](https://about.gitlab.com/pricing/).
GitLab system administrators can also take advantage of the logs located on the
file system. See [the logs system documentation](logs.md#audit_jsonlog) for more details.
GitLab system administrators can also view all audit events by accessing the [`audit_json.log` file](logs.md#audit_jsonlog).
You can:

View File

@ -10,7 +10,7 @@ GitLab has several features based on receiving incoming email messages:
- [Reply by Email](reply_by_email.md): allow GitLab users to comment on issues
and merge requests by replying to notification email.
- [New issue by email](../user/project/issues/managing_issues.md#new-issue-via-email):
- [New issue by email](../user/project/issues/managing_issues.md#by-sending-an-email):
allow GitLab users to create a new issue by sending an email to a
user-specific email address.
- [New merge request by email](../user/project/merge_requests/creating_merge_requests.md#by-sending-an-email):

View File

@ -133,7 +133,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- Instances.
- [Auditor users](auditor_users.md): Users with read-only access to all projects, groups, and other resources on the GitLab instance.
- [Incoming email](incoming_email.md): Configure incoming emails to allow
users to [reply by email](reply_by_email.md), create [issues by email](../user/project/issues/managing_issues.md#new-issue-via-email) and
users to [reply by email](reply_by_email.md), create [issues by email](../user/project/issues/managing_issues.md#by-sending-an-email) and
[merge requests by email](../user/project/merge_requests/creating_merge_requests.md#by-sending-an-email), and to enable [Service Desk](../user/project/service_desk.md).
- [Postfix for incoming email](reply_by_email_postfix_setup.md): Set up a
basic Postfix mail server with IMAP authentication on Ubuntu for incoming

View File

@ -9,14 +9,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
The CI/CD YAML reference uses a standard style to make it easier to use and update.
The reference information should be kept as simple as possible, and expanded details
and examples documented in a separate page.
and examples should be documented on other pages.
## YAML reference structure
Every YAML keyword must have its own section in the reference. The sections should
be nested so that the keywords follow a logical tree structure. For example:
```plaintext
```markdown
### `artifacts`
#### `artifacts:name`
#### `artifacts:paths`
@ -27,128 +27,127 @@ be nested so that the keywords follow a logical tree structure. For example:
## YAML reference style
Each keyword entry in the reference should use the following style:
Each keyword entry in the reference:
````markdown
### `keyword-name`
- Must have a simple introductory section. The introduction should give the fundamental
information needed to use the keyword. Advanced details and tasks should be in
feature pages, not the reference page.
> Version information
- Must use the keyword name as the title, for example:
Keyword description and main details.
```markdown
### `artifacts`
```
**Keyword type**:
- Should include the following sections:
- [Keyword type](#keyword-type)
- [Possible inputs](#possible-inputs)
- [Example of `keyword-name`](#example-of-keyword-name)
- (Optional) Can also include the following sections when needed:
- [Additional details](#additional-details)
- [Related topics](#related-topics)
The keyword name must always be in backticks without a final `:`, like `artifacts`, not `artifacts:`.
If it is a subkey of another keyword, write out all the subkeys to the "parent" key the first time it
is used, like `artifacts:reports:dast`. Afterwards, you can use just the subkey alone, like `dast`.
## Keyword type
The keyword can be either a job or global keyword. If it can be used in a `default`
section, make not of that as well, for example:
- `**Keyword type**: Global keyword.`
- `**Keyword type**: Job keyword. You can use it only as part of a job.`
- ``**Keyword type**: Job keyword. You can use it only as part of a job or in the [`default:` section](#default).``
### Possible inputs
List all the possible inputs, and any extra details about the inputs, such as defaults
or changes due to different GitLab versions, for example:
```markdown
**Possible inputs**:
**Example of `keyword-name`**:
(optional) In this example...
(optional) **Additional details**:
- List of extra details.
(optional) **Related topics**:
- List of links to topics related to the keyword.
````
- ``### `keyword-name` ``: The keyword name must always be in backticks.
If it is a subkey of another keyword, write out all the keywords, with each separated
by `:`, for example: `artifacts:reports:dast`.
- ``> Version information``: The [version history details](../documentation/styleguide/index.md#version-text-in-the-version-history).
If the keyword is feature flagged, see the [feature flag documentation guide](../documentation/feature_flags.md)
as well.
- `Keyword description and main details.`: A simple description of the keyword, and
how to use it. Additional use cases and benefits should be added to a page outside
the reference document. Link to that document in this section.
- `**Keyword type**:`: Most keywords are defined at the job level, like `script`,
or at the pipeline level, like `stages`. Add the appropriate line:
- `**Keyword type**: Job keyword. You can use it only as part of a job.`
- `**Keyword type**: Pipeline keyword. You cannot use it as part of a job.`
If a keyword can be used at both the job and pipeline level, like `variables`,
explain it in detail instead of using the pre-written lines above.
- `**Possible inputs**:`: Explain in detail which inputs the keyword can accept.
You can add the details in a sentence, paragraph, or list.
- ``**Example of `keyword-name`**:``: An example configuration that uses the keyword.
Do not add extra keywords that are not required to understand the behavior.
- (optional) `In this example...`: If the example needs extra details,
add the clarification text below the example.
- (optional) `**Additional details**:` If there are any caveats or extra details you
want to document along with the keyword, add each one as a list item here.
- (optional) `**Related topics**:` If there are any other keywords or pages that
relate to this keyword, add these links as list items here.
### YAML reference style example
See the [`only:changes` / `except:changes`](../../ci/yaml/index.md#onlychanges--exceptchanges)
documentation for an example of the YAML reference style. The following example is a
shortened version of that documentation's Markdown:
````markdown
#### `only:changes` / `except:changes`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/19232) in GitLab 11.4.
Use the `changes` keyword with `only` to run a job, or with `except` to skip a job,
when a Git push event modifies a file.
Use `changes` in pipelines with the following refs:
- `branches`
- `external_pull_requests`
- `merge_requests` (see additional details about [using `only:changes` with pipelines for merge requests](../jobs/job_control.md#use-onlychanges-with-pipelines-for-merge-requests))
**Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: An array including any number of:
- Paths to files.
- Wildcard paths for single directories, for example `path/to/directory/*`, or a directory
and all its subdirectories, for example `path/to/directory/**/*`.
**Example of `only:changes`**:
```yaml
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
only:
refs:
- branches
changes:
- Dockerfile
- docker/scripts/*
- dockerfiles/**/*
- `true` (default if not defined) or `false`.
```
In this example, `docker build` only runs in branch pipelines, and only if at least one of
these files changed:
```markdown
**Possible inputs**:
- `Dockerfile`.
- Any file in `docker/scripts`
- Any file in `dockerfiles/` or any of its subdirectories.
- A single exit code.
- An array of exit codes.
```
```markdown
**Possible inputs**:
- A string with the long description.
- The path to a file that contains the description. Introduced in [GitLab 13.7](https://gitlab.com/gitlab-org/release-cli/-/merge_requests/67).
- The file location must be relative to the project directory (`$CI_PROJECT_DIR`).
- If the file is a symbolic link, it must be in the `$CI_PROJECT_DIR`.
- The `./path/to/file` and filename can't contain spaces.
```
### Example of `keyword-name`
An example of the keyword. Use the minimum number of other keywords necessary
to make the example valid. If the example needs explanation, add it after the example,
for example:
````markdown
**Example of `dast`**:
```yaml
stages:
- build
- dast
include:
- template: DAST.gitlab-ci.yml
dast:
dast_configuration:
site_profile: "Example Co"
scanner_profile: "Quick Passive Test"
```
In this example, the `dast` job extends the `dast` configuration added with the `include:` keyword
to select a specific site profile and scanner profile.
````
### Additional details
The additional details should be an unordered list of extra information that is
useful to know, but not important enough to put in the introduction. This information
can include changes introduced in different GitLab versions. For example:
```markdown
**Additional details**:
- If you use refs other than `branches`, `external_pull_requests`, or `merge_requests`,
`changes` can't determine if a given file is new or old and always returns `true`.
- If you use `only: changes` with other refs, jobs ignore the changes and always run.
- If you use `except: changes` with other refs, jobs ignore the changes and never run.
- The expiration time period begins when the artifact is uploaded and stored on GitLab.
If the expiry time is not defined, it defaults to the [instance wide setting](../../user/admin_area/settings/continuous_integration.md#default-artifacts-expiration).
- To override the expiration date and protect artifacts from being automatically deleted:
- Select **Keep** on the job page.
- [In GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/22761), set the value of
`expire_in` to `never`.
```
### Related topics
The related topics should be an unordered list of crosslinks to related pages, including:
- Specific tasks that you can accomplish with the keyword.
- Advanced examples of the keyword.
- Other related keywords that can be used together with this keyword.
For example:
```markdown
**Related topics**:
- [`only: changes` and `except: changes` examples](../jobs/job_control.md#onlychanges--exceptchanges-examples).
- If you use `changes` with [only allow merge requests to be merged if the pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds),
you should [also use `only:merge_requests`](../jobs/job_control.md#use-onlychanges-with-pipelines-for-merge-requests).
- Use `changes` with [scheduled pipelines](../jobs/job_control.md#use-onlychanges-with-scheduled-pipelines).
````
- You can specify a [fallback cache key](../caching/index.md#use-a-fallback-cache-key)
to use if the specified `cache:key` is not found.
- You can [use multiple cache keys](../caching/index.md#use-multiple-caches) in a single job.
- See the [common `cache` use cases](../caching/index.md#common-use-cases-for-caches) for more
`cache:key` examples.
```

View File

@ -29,7 +29,7 @@ The following are guides to basic GitLab functionality:
- [Feature branch workflow](feature_branch_workflow.md).
- [Fork a project](../user/project/repository/forking_workflow.md#creating-a-fork), to duplicate projects so they can be worked on in parallel.
- [Add a file](add-file.md), to add new files to a project's repository.
- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue),
- [Create an issue](../user/project/issues/managing_issues.md#create-an-issue),
to start collaborating within a project.
- [Create a merge request](../user/project/merge_requests/creating_merge_requests.md), to request changes made in a branch
be merged into a project's repository.

View File

@ -116,6 +116,14 @@ Long term service and support (LTSS) for SUSE Linux Enterprise Server (SLES) 12
Announced: 2021-11-22
### Deprecation of bundler-audit Dependency Scanning tool
As of 14.6 bundler-audit is being deprecated from Dependency Scanning. It will continue to be in our CI/CD template while deprecated. We are removing bundler-audit from Dependency Scanning on May 22, 2022 in 15.0. After this removal Ruby scanning functionality will not be affected as it is still being covered by Gemnasium.
If you have explicitly excluded bundler-audit using DS_EXCLUDED_ANALYZERS you will need to clean up (remove the reference) in 15.0. If you have customized your pipeline's Dependency Scanning configuration, for example to edit the `bundler-audit-dependency_scanning` job, you will want to switch to gemnasium-dependency_scanning before removal in 15.0, to prevent your pipeline from failing. If you have not used the DS_EXCLUDED_ANALYZERS to reference bundler-audit, or customized your template specifically for bundler-audit, you will not need to take action.
Announced: 2021-12-22
### GitLab Serverless
[GitLab Serverless](https://docs.gitlab.com/ee/user/project/clusters/serverless/) is a feature set to support Knative-based serverless development with automatic deployments and monitoring.

View File

@ -71,7 +71,7 @@ To create the `.gitlab/issue_templates` directory:
1. Select **New directory**.
1. Name your directory `issue_templates` and commit to your default branch.
To check if this has worked correctly, [create a new issue](issues/managing_issues.md#create-a-new-issue)
To check if this has worked correctly, [create a new issue](issues/managing_issues.md#create-an-issue)
and see if you can choose a description template.
## Create a merge request template

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -29,7 +29,7 @@ To learn how the GitLab Strategic Marketing department uses GitLab issues with [
## Related topics
- [Create issues](managing_issues.md#create-a-new-issue)
- [Create issues](managing_issues.md#create-an-issue)
- [Create an issue from a template](../../project/description_templates.md#use-the-templates)
- [Edit issues](managing_issues.md#edit-an-issue)
- [Move issues](managing_issues.md#moving-issues)

View File

@ -4,148 +4,228 @@ group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Managing issues **(FREE)**
# Manage issues **(FREE)**
[GitLab Issues](index.md) are the fundamental medium for collaborating on ideas and
planning work in GitLab.
Key actions for issues include:
## Create an issue
- [Creating issues](#create-a-new-issue)
- [Moving issues](#moving-issues)
- [Closing issues](#closing-issues)
- [Deleting issues](#deleting-issues)
- [Promoting issues](#promote-an-issue-to-an-epic) **(PREMIUM)**
## Create a new issue
When you create a new issue, you are prompted to enter the fields of the issue.
When you create an issue, you are prompted to enter the fields of the issue.
If you know the values you want to assign to an issue, you can use
[quick actions](../quick_actions.md) to enter them.
While creating an issue, you can associate it to an existing epic from current group by
selecting it using **Epic** dropdown.
You can create an issue in many ways in GitLab:
### Accessing the New Issue form
- [From a project](#from-a-project)
- [From a group](#from-a-group)
- [From another issue](#from-another-issue)
- [From an issue board](#from-an-issue-board)
- [By sending an email](#by-sending-an-email)
- Using a URL with prefilled fields
- [Using Service Desk](#using-service-desk)
There are many ways to get to the New Issue form from a project's page:
### From a project
- Navigate to your **Project's Dashboard** > **Issues** > **New Issue**:
Prerequisites:
![New issue from the issue list view](img/new_issue_from_tracker_list.png)
- You must have at least the [Guest role](../../permissions.md) for the project.
- From an **open issue** in your project, click the vertical ellipsis (**{ellipsis_v}**) button
to open a dropdown menu, and then click **New Issue** to create a new issue in the same project:
To create an issue:
![New issue from an open issue](img/new_issue_from_open_issue_v13_6.png)
1. On the top bar, select **Menu > Projects** and find your project.
1. Either:
- From your **Project's Dashboard**, click the plus sign (**+**) to open a dropdown
menu with a few options. Select **New Issue** to create an issue in that project:
- On the left sidebar, select **Issues**, and then, in the top right corner, select **New issue**.
- On the top bar, select the plus sign (**{plus-square}**) and then, under **This project**,
select **New issue**.
![New issue from a project's dashboard](img/new_issue_from_projects_dashboard.png)
1. Complete the [fields](#fields-in-the-new-issue-form).
1. Select **Create issue**.
- From an **issue board**, create a new issue by clicking on the plus sign (**+**) at the top of a list.
It opens a new issue for that project, pre-labeled with its respective list.
The newly created issue opens.
![From the issue board](img/new_issue_from_issue_board.png)
### From a group
### Elements of the New Issue form
Issues belong to projects, but when you're in a group, you can access and create issues that belong
to the projects in the group.
> Ability to add the new issue to an epic [was introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13847) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.1.
Prerequisites:
![New issue from the issues list](img/new_issue_v13_1.png)
- You must have at least the [Guest role](../../permissions.md) for a project in the group.
When you're creating a new issue, these are the fields you can fill in:
To create an issue from a group:
- Title
- Description
- Checkbox to make the issue [confidential](confidential_issues.md)
- Assignee
- Weight
- [Epic](../../group/epics/index.md)
- Due date
- Milestone
- Labels
### New issue from the group-level issue tracker
To visit the issue tracker for all projects in your group:
1. Go to the group dashboard.
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Issues**.
1. In the top-right, select the **Select project to create issue** button.
1. In the top right corner, select **Select project to create issue**.
1. Select the project you'd like to create an issue for. The button now reflects the selected
project.
1. Select the button to create an issue in the selected project.
1. Select **New issue in `<project name>`**.
1. Complete the [fields](#fields-in-the-new-issue-form).
1. Select **Create issue**.
![Select project to create issue](img/select_project_from_group_level_issue_tracker_v13_11.png)
The newly created issue opens.
The project you selected most recently becomes the default for your next visit.
This should save you a lot of time and clicks, if you mostly create issues for the same project.
This can save you a lot of time and clicks, if you mostly create issues for the same project.
### New issue via Service Desk
### From another issue
Enable [Service Desk](../service_desk.md) for your project and offer email support.
Now, when your customer sends a new email, a new issue can be created in
the appropriate project and followed up from there.
> New issue becoming linked to the issue of origin [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68226) in GitLab 14.3.
### New issue via email
You can create a new issue from an existing one. The two issues can then be marked as related.
A link to **Email a new issue to this project** is displayed at the bottom of a project's
**Issues List** page. The link is shown only if your GitLab instance has [incoming email](../../../administration/incoming_email.md)
configured and there is at least one issue in the issue list.
Prerequisites:
![Bottom of a project issues page](img/new_issue_from_email.png)
- You must have at least the [Guest role](../../permissions.md) for the project.
When you click this link, an email address is generated and displayed, which should be used
by **you only**, to create issues in this project. You can save this address as a
contact in your email client for quick access.
To create an issue from another issue:
1. In an existing issue, select the vertical ellipsis (**{ellipsis_v}**).
1. Select **New issue**.
1. Complete the [fields](#fields-in-the-new-issue-form).
The new issue's description is prefilled with `Related to #123`, where `123` is the ID of the
issue of origin. If you keep this mention in the description, the two issues become
[linked](related_issues.md).
1. Select **Create issue**.
The newly created issue opens.
### From an issue board
You can create a new issue from an [issue board](../issue_board.md).
Prerequisites:
- You must have at least the [Guest role](../../permissions.md) for the project.
To create an issue from a project issue board:
1. On the top bar, select **Menu > Projects** and find your project.
1. Select **Issues > Boards**.
1. At the top of a board list, select **New issue** (**{plus-square}**).
1. Enter the issue's title.
1. Select **Create issue**.
To create an issue from a group issue board:
1. On the top bar, select **Menu > Groups** and find your group.
1. Select **Issues > Boards**.
1. At the top of a board list, select **New issue** (**{plus-square}**).
1. Enter the issue's title.
1. Under **Projects**, select the project in the group that the issue should belong to.
1. Select **Create issue**.
The issue is created and shows up in the board list. It shares the list's characteristic, so, for
example, if the list is scoped to a label `Frontend`, the new issue also has this label.
### By sending an email
> Generated email address format changed in GitLab 11.7.
> The older format is still supported, so existing aliases and contacts still work.
You can send an email to create an issue in a project on the project's
**Issues List** page.
Prerequisites:
- Your GitLab instance must have [incoming email](../../../administration/incoming_email.md)
configured.
- There must be at least one issue in the issue list.
- You must have at least the [Guest role](../../permissions.md) for the project.
To email an issue to a project:
1. On the top bar, select **Menu > Projects** and find your project.
1. Select **Issues**.
1. At the bottom of the page, select **Email a new issue to this project**.
1. To copy the email address, select **Copy** (**{copy-to-clipboard}**).
1. From your email client, send an email to this address.
The subject is used as the title of the new issue, and the email body becomes the description.
You can use [Markdown](../../markdown.md) and [quick actions](../quick_actions.md).
A new issue is created, with your user as the author.
You can save this address as a contact in your email client to use it again.
WARNING:
This is a private email address, generated just for you. **Keep it to yourself**,
as anyone who knows it can create issues or merge requests as if they
were you. If the address is compromised, or you want to regenerate it,
click **Email a new issue to this project**, followed by **reset it**.
The email address you see is a private email address, generated just for you.
**Keep it to yourself**, because anyone who knows it can create issues or merge requests as if they
were you.
Sending an email to this address creates a new issue associated with your account for
this project, where:
To regenerate the email address:
- The email subject becomes the issue title.
- The email body becomes the issue description.
- [Markdown](../../markdown.md) and [quick actions](../quick_actions.md) are supported.
1. On the issues list, select **Email a new issue to this project**.
1. Select **reset this token**.
NOTE:
In GitLab 11.7, we updated the format of the generated email address. However the
older format is still supported, allowing existing aliases or contacts to continue working.
### New issue via URL with prefilled fields
### Using a URL with prefilled values
To link directly to the new issue page with prefilled fields, use query
string parameters in a URL. You can embed a URL in an external
HTML page to create issues with certain
fields prefilled.
HTML page to create issues with certain fields prefilled.
| Field | URL Parameter Name | Notes |
|----------------------|-----------------------|-------------------------------------------------------|
| title | `issue[title]` | |
| description | `issue[description]` | Cannot be used at the same time as `issuable_template`. |
| description template | `issuable_template` | Cannot be used at the same time as `issue[description]`. |
| issue type | `issue[issue_type]` | Either `incident` or `issue`. |
| confidential | `issue[confidential]` | Parameter value must be `true` to set to confidential. |
| Field | URL parameter | Notes |
| -------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Title | `issue[title]` | Must be [URL-encoded](../../../api/index.md#namespaced-path-encoding). |
| Issue type | `issue[issue_type]` | Either `incident` or `issue`. |
| Description template | `issuable_template` | Cannot be used at the same time as `issue[description]`. Must be [URL-encoded](../../../api/index.md#namespaced-path-encoding). |
| Description | `issue[description]` | Cannot be used at the same time as `issuable_template`. Must be [URL-encoded](../../../api/index.md#namespaced-path-encoding). |
| Confidential | `issue[confidential]` | If `true`, the issue is marked as confidential. |
Follow these examples to form your new issue URL with prefilled fields.
Adapt these examples to form your new issue URL with prefilled fields.
To create an issue in the GitLab project:
- For a new issue in the GitLab Community Edition project with a pre-filled title
and a pre-filled description, the URL would be `https://gitlab.com/gitlab-org/gitlab-foss/-/issues/new?issue[title]=Validate%20new%20concept&issue[description]=Research%20idea`
- For a new issue in the GitLab Community Edition project with a pre-filled title
and a pre-filled description template, the URL would be `https://gitlab.com/gitlab-org/gitlab-foss/-/issues/new?issue[title]=Validate%20new%20concept&issuable_template=Research%20proposal`
- For a new issue in the GitLab Community Edition project with a pre-filled title,
a pre-filled description, and the confidential flag set, the URL would be `https://gitlab.com/gitlab-org/gitlab-foss/-/issues/new?issue[title]=Validate%20new%20concept&issue[description]=Research%20idea&issue[confidential]=true`
- With a prefilled title and description:
```plaintext
https://gitlab.com/gitlab-org/gitlab/-/issues/new?issue[title]=Whoa%2C%20we%27re%20half-way%20there&issue[description]=Whoa%2C%20livin%27%20in%20a%20URL
```
- With a prefilled title and description template:
```plaintext
https://gitlab.com/gitlab-org/gitlab/-/issues/new?issue[title]=Validate%20new%20concept&issuable_template=Feature%20Proposal%20-%20basic
```
- With a prefilled title, description, and marked as confidential:
```plaintext
https://gitlab.com/gitlab-org/gitlab/-/issues/new?issue[title]=Validate%20new%20concept&issue[description]=Research%20idea&issue[confidential]=true
```
### Using Service Desk
To offer email support, enable [Service Desk](../service_desk.md) for your project.
Now, when your customer sends a new email, a new issue can be created in
the appropriate project and followed up from there.
### Fields in the new issue form
> Adding the new issue to an epic [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13847) in GitLab 13.1.
When you're creating a new issue, you can complete the following fields:
- Title
- Type: either issue (default) or incident
- [Description template](../description_templates.md): overwrites anything in the Description text box
- Description: you can use [Markdown](../../markdown.md) and [quick actions](../quick_actions.md)
- Checkbox to make the issue [confidential](confidential_issues.md)
- [Assignees](#assignee)
- [Weight](issue_weight.md)
- [Epic](../../group/epics/index.md)
- [Due date](due_dates.md)
- [Milestone](../milestones/index.md)
- [Labels](../labels.md)
## Edit an issue
You can edit an issue's title and description.
Prerequisites:
- You must have at least the [Reporter role](../../permissions.md) for a project.
To edit an issue, select **Edit title and description** (**{pencil}**).
### Bulk edit issues at the project level

View File

@ -4,7 +4,7 @@ group: Workspace
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
---
# Working with projects **(FREE)**
# Manage projects **(FREE)**
Most work in GitLab is done in a [project](../../user/project/index.md). Files and
code are saved in projects, and most features are in the scope of projects.
@ -16,7 +16,7 @@ To explore projects:
1. On the top bar, select **Menu > Projects**.
1. Select **Explore projects**.
GitLab displays a list of projects, sorted by last updated date.
The **Projects** page shows a list of projects, sorted by last updated date.
- To view projects with the most [stars](#star-a-project), select **Most stars**.
- To view projects with the largest number of comments in the past month, select **Trending**.
@ -26,14 +26,37 @@ The **Explore projects** tab is visible to unauthenticated users unless the
[**Public** visibility level](../admin_area/settings/visibility_and_access_controls.md#restrict-visibility-levels)
is restricted. Then the tab is visible only to signed-in users.
### Who can view the **Projects** page
When you select a project, the project landing page shows the project contents.
For public projects, and members of internal and private projects
with [permissions to view the project's code](../permissions.md#project-members-permissions),
the project landing page shows:
- A [`README` or index file](repository/index.md#readme-and-index-files).
- A list of directories in the project's repository.
For users without permission to view the project's code, the landing page shows:
- The wiki homepage.
- The list of issues in the project.
### Access a project page with the project ID
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53671) in GitLab 11.8.
To access a project from the GitLab UI using the project ID,
visit the `/projects/:id` URL in your browser or other tool accessing the project.
## Explore topics
You can explore popular project topics available on GitLab. To explore project topics:
To explore project topics:
1. On the top bar, select **Menu > Projects**.
1. Select **Explore topics**.
GitLab displays a list of topics sorted by the number of associated projects.
The **Projects** page shows list of topics sorted by the number of associated projects.
To view projects associated with a topic, select a topic from the list.
You can assign topics to a project on the [Project Settings page](settings/index.md#topics).
@ -260,9 +283,8 @@ To add a star to a project:
## Delete a project
After you delete a project, projects in personal namespaces are deleted immediately. You can
[enable delayed project removal](../group/index.md#enable-delayed-project-deletion) to
delay deletion of projects in a group.
After you delete a project, projects in personal namespaces are deleted immediately. To delay deletion of projects in a group
you can [enable delayed project removal](../group/index.md#enable-delayed-project-deletion).
To delete a project:
@ -299,56 +321,27 @@ To leave a project:
on the project dashboard when a project is part of a group under a
[group namespace](../group/index.md#namespaces).
## Use your project as a Go package
## Use a project as a Go package
Any project can be used as a Go package. GitLab responds correctly to `go get`
and `godoc.org` discovery requests, including the
[`go-import`](https://golang.org/cmd/go/#hdr-Remote_import_paths) and
[`go-source`](https://github.com/golang/gddo/wiki/Source-Code-Links) meta tags.
Prerequisites:
Private projects, including projects in subgroups, can be used as a Go package.
These projects may require configuration to work correctly. GitLab responds correctly
to `go get` discovery requests for projects that *are not* in subgroups,
regardless of authentication or authorization.
[Authentication](#authenticate-go-requests) is required to use a private project
in a subgroup as a Go package. Otherwise, GitLab truncates the path for
private projects in subgroups to the first two segments, causing `go get` to
fail.
- Contact your administrator to enable the [GitLab Go Proxy](../packages/go_proxy/index.md).
- To use a private project in a subgroup as a Go package, you must [authenticate Go requests](#authenticate-go-requests-to-private-projects). Go requests that are not authenticated cause
`go get` to fail. You don't need to authenticate Go requests for projects that are not in subgroups.
GitLab implements its own Go proxy. This feature must be enabled by an
administrator and requires additional configuration. See [GitLab Go
Proxy](../packages/go_proxy/index.md).
To use a project as a Go package, use the `go get` and `godoc.org` discovery requests. You can use the meta tags:
### Disable Go module features for private projects
- [`go-import`](https://golang.org/cmd/go/#hdr-Remote_import_paths)
- [`go-source`](https://github.com/golang/gddo/wiki/Source-Code-Links)
In Go 1.12 and later, Go queries module proxies and checksum databases in the
process of [fetching a
module](../../development/go_guide/dependencies.md#fetching). This can be
selectively disabled with `GOPRIVATE` (disable both),
[`GONOPROXY`](../../development/go_guide/dependencies.md#proxies) (disable proxy
queries), and [`GONOSUMDB`](../../development/go_guide/dependencies.md#fetching)
(disable checksum queries).
### Authenticate Go requests to private projects
`GOPRIVATE`, `GONOPROXY`, and `GONOSUMDB` are comma-separated lists of Go
modules and Go module prefixes. For example,
`GOPRIVATE=gitlab.example.com/my/private/project` disables queries for that
one project, but `GOPRIVATE=gitlab.example.com` disables queries for *all*
projects on GitLab.com. Go does not query module proxies if the module name or a
prefix of it appears in `GOPRIVATE` or `GONOPROXY`. Go does not query checksum
databases if the module name or a prefix of it appears in `GONOPRIVATE` or
`GONOSUMDB`.
Prerequisites:
### Authenticate Go requests
- Your GitLab instance must be accessible with HTTPS.
- You must have a [personal access token](../profile/personal_access_tokens.md).
To authenticate requests to private projects made by Go, use a [`.netrc`
file](https://everything.curl.dev/usingcurl/netrc) and a [personal access
token](../profile/personal_access_tokens.md) in the password field. **This only
works if your GitLab instance can be accessed with HTTPS.** The `go` command
does not transmit credentials over insecure connections. This authenticates
all HTTPS requests made directly by Go, but does not authenticate requests made
through Git.
For example:
To authenticate Go requests, create a [`.netrc`](https://everything.curl.dev/usingcurl/netrc) file with the following information:
```plaintext
machine gitlab.example.com
@ -356,98 +349,106 @@ login <gitlab_user_name>
password <personal_access_token>
```
NOTE:
On Windows, Go reads `~/_netrc` instead of `~/.netrc`.
### Authenticate Git fetches
The `go` command does not transmit credentials over insecure connections. It authenticates
HTTPS requests made by Go, but does not authenticate requests made
through Git.
If a module cannot be fetched from a proxy, Go falls back to using Git (for
GitLab projects). Git uses `.netrc` to authenticate requests. You can also
configure Git to either:
### Authenticate Git requests
- Embed specific credentials in the request URL.
- Use SSH instead of HTTPS, as Go always uses HTTPS to fetch Git repositories.
If Go cannot fetch a module from a proxy, it uses Git. Git uses a `.netrc` file to authenticate requests, but you can
configure other authentication methods.
```shell
# Embed credentials in any request to GitLab.com:
git config --global url."https://${user}:${personal_access_token}@gitlab.example.com".insteadOf "https://gitlab.example.com"
Configure Git to either:
# Use SSH instead of HTTPS:
git config --global url."git@gitlab.example.com".insteadOf "https://gitlab.example.com"
```
- Embed credentials in the request URL:
```shell
git config --global url."https://${user}:${personal_access_token}@gitlab.example.com".insteadOf "https://gitlab.example.com"
```
- Use SSH instead of HTTPS:
```shell
git config --global url."git@gitlab.example.com".insteadOf "https://gitlab.example.com"
```
### Disable Go module fetching for private projects
To [fetch modules or packages](../../development/go_guide/dependencies.md#fetching), Go uses
the [environment variables](../../development/go_guide/dependencies.md#proxies):
- `GOPRIVATE`
- `GONOPROXY`
- `GONOSUMDB`
To disable fetching:
1. Disable `GOPRIVATE`:
- To disable queries for one project, disable `GOPRIVATE=gitlab.example.com/my/private/project`.
- To disable queries for all projects on GitLab.com, disable `GOPRIVATE=gitlab.example.com`.
1. Disable proxy queries in `GONOPROXY`.
1. Disable checksum queries in `GONOSUMDB`.
- If the module name or its prefix is in `GOPRIVATE` or `GONOPROXY`, Go does not query module
proxies.
- If the module name or its prefix is in `GONOPRIVATE` or `GONOSUMDB`, Go does not query
Checksum databases.
### Fetch Go modules from Geo secondary sites
As Go modules are stored in Git repositories, you can use the [Geo](../../administration/geo/index.md)
feature that allows Git repositories to be accessed on the secondary Geo servers.
Use [Geo](../../administration/geo/index.md) to access Git repositories that contain Go modules
on secondary Geo servers.
In the following examples, the primary's site domain name is `gitlab.example.com`,
and the secondary's is `gitlab-secondary.example.com`.
You can use SSH or HTTP to access the Geo secondary server.
`go get` will initially generate some HTTP traffic to the primary, but when the module
download commences, the `insteadOf` configuration sends the traffic to the secondary.
#### Use SSH to access the Geo secondary server
#### Use SSH to access the Geo secondary
To fetch Go modules from the secondary using SSH:
To access the Geo secondary server with SSH:
1. Reconfigure Git on the client to send traffic for the primary to the secondary:
```plaintext
```shell
git config --global url."git@gitlab-secondary.example.com".insteadOf "https://gitlab.example.com"
git config --global url."git@gitlab-secondary.example.com".insteadOf "http://gitlab.example.com"
```
1. Ensure the client is set up for SSH access to GitLab repositories. This can be tested on the primary,
and GitLab will replicate the public key to the secondary.
- For `gitlab.example.com`, use the primary site domain name.
- For `gitlab-secondary.example.com`, use the secondary site domain name.
1. Ensure the client is set up for SSH access to GitLab repositories. You can test this on the primary,
and GitLab replicates the public key to the secondary.
The `go get` request generates HTTP traffic to the primary Geo server. When the module
download starts, the `insteadOf` configuration sends the traffic to the secondary Geo server.
#### Use HTTP to access the Geo secondary
Using HTTP to fetch Go modules does not work with CI/CD job tokens, only with
persistent access tokens that are replicated to the secondary.
You must use persistent access tokens that replicate to the secondary server. You cannot use
CI/CD job tokens to fetch Go modules with HTTP.
To fetch Go modules from the secondary using HTTP:
To access the Geo secondary server with HTTP:
1. Put in place a Git `insteadOf` redirect on the client:
1. Add a Git `insteadOf` redirect on the client:
```plaintext
```shell
git config --global url."https://gitlab-secondary.example.com".insteadOf "https://gitlab.example.com"
```
1. Generate a [personal access token](../profile/personal_access_tokens.md) and
provide those credentials in the client's `~/.netrc` file:
- For `gitlab.example.com`, use the primary site domain name.
- For `gitlab-secondary.example.com`, use the secondary site domain name.
```plaintext
1. Generate a [personal access token](../profile/personal_access_tokens.md) and
add the credentials in the client's `~/.netrc` file:
```shell
machine gitlab.example.com login USERNAME password TOKEN
machine gitlab-secondary.example.com login USERNAME password TOKEN
```
## Access project page with project ID
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53671) in GitLab 11.8.
To quickly access a project from the GitLab UI using the project ID,
visit the `/projects/:id` URL in your browser or other tool accessing the project.
## Project's landing page
The project's landing page shows different information depending on
the project's visibility settings and user permissions.
For public projects, and to members of internal and private projects
with [permissions to view the project's code](../permissions.md#project-members-permissions):
- The content of a
[`README` or an index file](repository/index.md#readme-and-index-files)
is displayed (if any), followed by the list of directories in the
project's repository.
- If the project doesn't contain either of these files, the
visitor sees the list of files and directories of the repository.
For users without permissions to view the project's code, GitLab displays:
- The wiki homepage, if any.
- The list of issues in the project.
The `go get` request generates HTTP traffic to the primary Geo server. When the module
download starts, the `insteadOf` configuration sends the traffic to the secondary Geo server.
## Related topics

View File

@ -11,11 +11,11 @@
variables:
FUZZAPI_VERSION: "1"
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
FUZZAPI_IMAGE: ${SECURE_ANALYZERS_PREFIX}/api-fuzzing:${FUZZAPI_VERSION}
FUZZAPI_IMAGE: api-fuzzing
apifuzzer_fuzz:
stage: fuzz
image: $FUZZAPI_IMAGE
image: $SECURE_ANALYZERS_PREFIX/$FUZZAPI_IMAGE:$FUZZAPI_VERSION
allow_failure: true
rules:
- if: $API_FUZZING_DISABLED

View File

@ -0,0 +1,52 @@
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Dast-API.gitlab-ci.yml
# To use this template, add the following to your .gitlab-ci.yml file:
#
# include:
# template: DAST-API.latest.gitlab-ci.yml
#
# You also need to add a `dast` stage to your `stages:` configuration. A sample configuration for DAST API:
#
# stages:
# - build
# - test
# - deploy
# - dast
# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/dast_api/index.html
# Configure DAST API scanning with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html).
# List of available variables: https://docs.gitlab.com/ee/user/application_security/dast_api/index.html#available-cicd-variables
variables:
# Setting this variable affects all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
#
DAST_API_VERSION: "1"
DAST_API_IMAGE: api-fuzzing
dast_api:
stage: dast
image: $SECURE_ANALYZERS_PREFIX/$DAST_API_IMAGE:$DAST_API_VERSION
allow_failure: true
rules:
- if: $DAST_API_DISABLED
when: never
- if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH
script:
- /peach/analyzer-dast-api
artifacts:
when: always
paths:
- gl-assets
- gl-dast-api-report.json
- gl-*.log
reports:
dast: gl-dast-api-report.json

View File

@ -11,19 +11,20 @@ module Gitlab
end
def trace(key, data)
result = yield
yield
rescue StandardError => e
data[:exception] = e
raise e
ensure
case key
when "execute_query"
log_execute_query(**data)
end
result
end
private
def log_execute_query(query: nil, duration_s: 0)
def log_execute_query(query: nil, duration_s: 0, exception: nil)
# execute_query should always have :query, but we're just being defensive
return unless query
@ -39,6 +40,8 @@ module Gitlab
query_string: query.query_string
}
Gitlab::ExceptionLogFormatter.format!(exception, info)
info.merge!(::Gitlab::ApplicationContext.current)
info.merge!(analysis_info) if analysis_info

View File

@ -17,13 +17,9 @@ module Gitlab
def trace(key, data)
start_time = Gitlab::Metrics::System.monotonic_time
result = yield
duration_s = Gitlab::Metrics::System.monotonic_time - start_time
data[:duration_s] = duration_s
result
yield
ensure
data[:duration_s] = Gitlab::Metrics::System.monotonic_time - start_time
end
end
end

View File

@ -119,6 +119,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_api_latest
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_container_scanning
category: ci_templates
redis_slot: ci_templates
@ -551,6 +555,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_dast_api_latest
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_container_scanning
category: ci_templates
redis_slot: ci_templates

View File

@ -5,7 +5,6 @@ module QA
module Project
module Settings
class Advanced < Page::Base
include Component::Select2
include Component::ConfirmModal
view 'app/views/projects/edit.html.haml' do
@ -13,8 +12,10 @@ module QA
element :change_path_button
end
view 'app/views/projects/_transfer.html.haml' do
element :transfer_button
view "app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue" do
element :namespaces_list
element :namespaces_list_groups
element :namespaces_list_item
end
view 'app/views/projects/settings/_archive.html.haml' do
@ -42,16 +43,22 @@ module QA
click_element :change_path_button
end
def select_namespace(item)
click_element :namespaces_list
within_element(:namespaces_list) do
find_element(:namespaces_list_item, text: item).click
end
end
def transfer_project!(project_name, namespace)
QA::Runtime::Logger.info "Transferring project: #{project_name} to namespace: #{namespace}"
click_element_coordinates(:archive_project_content)
expand_select_list
# Workaround for a failure to search when there are no spaces around the /
# https://gitlab.com/gitlab-org/gitlab/-/issues/218965
search_and_select(namespace.gsub(%r{([^\s])/([^\s])}, '\1 / \2'))
select_namespace(namespace.gsub(%r{([^\s])/([^\s])}, '\1 / \2'))
click_element(:transfer_button)
fill_confirmation_text(project_name)

View File

@ -899,10 +899,34 @@ RSpec.describe ProjectsController do
describe '#transfer', :enable_admin_mode do
render_views
let_it_be(:project, reload: true) { create(:project) }
let(:project) { create(:project) }
let_it_be(:admin) { create(:admin) }
let_it_be(:new_namespace) { create(:namespace) }
shared_examples 'project namespace is not changed' do |flash_message|
it 'project namespace is not changed' do
controller.instance_variable_set(:@project, project)
sign_in(admin)
old_namespace = project.namespace
put :transfer,
params: {
namespace_id: old_namespace.path,
new_namespace_id: new_namespace_id,
id: project.path
},
format: :js
project.reload
expect(project.namespace).to eq(old_namespace)
expect(response).to redirect_to(edit_project_path(project))
expect(flash[:alert]).to eq flash_message
end
end
it 'updates namespace' do
sign_in(admin)
@ -921,26 +945,15 @@ RSpec.describe ProjectsController do
end
context 'when new namespace is empty' do
it 'project namespace is not changed' do
controller.instance_variable_set(:@project, project)
sign_in(admin)
let(:new_namespace_id) { nil }
old_namespace = project.namespace
it_behaves_like 'project namespace is not changed', s_('TransferProject|Please select a new namespace for your project.')
end
put :transfer,
params: {
namespace_id: old_namespace.path,
new_namespace_id: nil,
id: project.path
},
format: :js
context 'when new namespace is the same as the current namespace' do
let(:new_namespace_id) { project.namespace.id }
project.reload
expect(project.namespace).to eq(old_namespace)
expect(response).to have_gitlab_http_status(:ok)
expect(flash[:alert]).to eq s_('TransferProject|Please select a new namespace for your project.')
end
it_behaves_like 'project namespace is not changed', s_('TransferProject|Project is already in this namespace.')
end
end

View File

@ -44,4 +44,90 @@ RSpec.describe 'Blob shortcuts', :js do
include_examples 'quotes the selected text'
end
end
shared_examples "opens assignee dropdown for editing" do
it "opens assignee dropdown for editing" do
find('body').native.send_key('a')
expect(find('.block.assignee')).to have_selector('.js-sidebar-assignee-data')
end
end
describe 'pressing "a"' do
describe 'On an Issue' do
before do
stub_feature_flags(issue_assignees_widget: false)
visit project_issue_path(project, issue)
wait_for_requests
end
include_examples 'opens assignee dropdown for editing'
end
describe 'On a Merge Request' do
before do
stub_feature_flags(issue_assignees_widget: false)
visit project_merge_request_path(project, merge_request)
wait_for_requests
end
include_examples 'opens assignee dropdown for editing'
end
end
shared_examples "opens milestones dropdown for editing" do
it "opens milestones dropdown for editing" do
find('body').native.send_key('m')
expect(find('[data-testid="milestone-edit"]')).to have_selector('.gl-new-dropdown-inner')
end
end
describe 'pressing "m"' do
describe 'On an Issue' do
before do
visit project_issue_path(project, issue)
wait_for_requests
end
include_examples 'opens milestones dropdown for editing'
end
describe 'On a Merge Request' do
before do
visit project_merge_request_path(project, merge_request)
wait_for_requests
end
include_examples 'opens milestones dropdown for editing'
end
end
shared_examples "opens labels dropdown for editing" do
it "opens labels dropdown for editing" do
find('body').native.send_key('l')
expect(find('.js-labels-block')).to have_selector('[data-testid="labels-select-dropdown-contents"]')
end
end
describe 'pressing "l"' do
describe 'On an Issue' do
before do
visit project_issue_path(project, issue)
wait_for_requests
end
include_examples 'opens labels dropdown for editing'
end
describe 'On a Merge Request' do
before do
visit project_merge_request_path(project, merge_request)
wait_for_requests
end
include_examples 'opens labels dropdown for editing'
end
end
end

View File

@ -8,6 +8,8 @@ RSpec.describe 'Projects > Settings > User transfers a project', :js do
let(:group) { create(:group) }
before do
stub_const('Gitlab::QueryLimiting::Transaction::THRESHOLD', 120)
group.add_owner(user)
sign_in(user)
end
@ -16,10 +18,12 @@ RSpec.describe 'Projects > Settings > User transfers a project', :js do
visit edit_project_path(project)
page.within('.js-project-transfer-form') do
page.find('.select2-container').click
page.find('[data-testid="transfer-project-namespace"]').click
end
page.find("div[role='option']", text: group.full_name).click
page.within('[data-testid="transfer-project-namespace"]') do
page.find("li button", text: group.full_name).click
end
click_button('Transfer project')

View File

@ -0,0 +1,68 @@
import { namespaces } from 'jest/vue_shared/components/namespace_select/mock_data';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import TransferProjectForm from '~/projects/settings/components/transfer_project_form.vue';
import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select.vue';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
describe('Transfer project form', () => {
let wrapper;
const confirmButtonText = 'Confirm';
const confirmationPhrase = 'You must construct additional pylons!';
const createComponent = () =>
shallowMountExtended(TransferProjectForm, {
propsData: {
namespaces,
confirmButtonText,
confirmationPhrase,
},
});
const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect);
const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger);
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders the namespace selector', () => {
expect(findNamespaceSelect().exists()).toBe(true);
});
it('renders the confirm button', () => {
expect(findConfirmDanger().exists()).toBe(true);
});
it('disables the confirm button by default', () => {
expect(findConfirmDanger().attributes('disabled')).toBe('true');
});
describe('with a selected namespace', () => {
const [selectedItem] = namespaces.group;
beforeEach(() => {
findNamespaceSelect().vm.$emit('select', selectedItem);
});
it('emits the `selectNamespace` event when a namespace is selected', () => {
const args = [selectedItem.id];
expect(wrapper.emitted('selectNamespace')).toEqual([args]);
});
it('enables the confirm button', () => {
expect(findConfirmDanger().attributes('disabled')).toBeUndefined();
});
it('clicking the confirm button emits the `confirm` event', () => {
findConfirmDanger().vm.$emit('confirm');
expect(wrapper.emitted('confirm')).toBeDefined();
});
});
});

View File

@ -4,11 +4,11 @@ import { loadHTMLFixture } from 'helpers/fixtures';
import setupTransferEdit from '~/transfer_edit';
describe('setupTransferEdit', () => {
const formSelector = '.js-project-transfer-form';
const targetSelector = 'select.select2';
const formSelector = '.js-group-transfer-form';
const targetSelector = '#new_parent_group_id';
beforeEach(() => {
loadHTMLFixture('projects/edit.html');
loadHTMLFixture('groups/edit.html');
setupTransferEdit(formSelector, targetSelector);
});
@ -17,8 +17,8 @@ describe('setupTransferEdit', () => {
});
it('enables submit button when selection changes to non-empty value', () => {
const nonEmptyValue = $(formSelector).find(targetSelector).find('option').not(':empty').val();
$(formSelector).find(targetSelector).val(nonEmptyValue).trigger('change');
const lastValue = $(formSelector).find(targetSelector).find('.dropdown-content li').last();
$(formSelector).find(targetSelector).val(lastValue).trigger('change');
expect($(formSelector).find(':submit').prop('disabled')).toBeFalsy();
});

View File

@ -0,0 +1,11 @@
export const group = [
{ id: 1, name: 'Group 1', humanName: 'Group 1' },
{ id: 2, name: 'Subgroup 1', humanName: 'Group 1 / Subgroup 1' },
];
export const user = [{ id: 3, name: 'User namespace 1', humanName: 'User namespace 1' }];
export const namespaces = {
group,
user,
};

View File

@ -0,0 +1,86 @@
import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NamespaceSelect, {
i18n,
} from '~/vue_shared/components/namespace_select/namespace_select.vue';
import { user, group, namespaces } from './mock_data';
describe('Namespace Select', () => {
let wrapper;
const createComponent = (props = {}) =>
shallowMountExtended(NamespaceSelect, {
propsData: {
data: namespaces,
...props,
},
});
const wrappersText = (arr) => arr.wrappers.map((w) => w.text());
const flatNamespaces = () => [...group, ...user];
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownAttributes = (attr) => findDropdown().attributes(attr);
const selectedDropdownItemText = () => findDropdownAttributes('text');
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findSectionHeaders = () => wrapper.findAllComponents(GlDropdownSectionHeader);
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders the dropdown', () => {
expect(findDropdown().exists()).toBe(true);
});
it('renders each dropdown item', () => {
const items = findDropdownItems().wrappers;
expect(items).toHaveLength(flatNamespaces().length);
});
it('renders the human name for each item', () => {
const dropdownItems = wrappersText(findDropdownItems());
const flatNames = flatNamespaces().map(({ humanName }) => humanName);
expect(dropdownItems).toEqual(flatNames);
});
it('sets the initial dropdown text', () => {
expect(selectedDropdownItemText()).toBe(i18n.DEFAULT_TEXT);
});
it('splits group and user namespaces', () => {
const headers = findSectionHeaders();
expect(headers).toHaveLength(2);
expect(wrappersText(headers)).toEqual([i18n.GROUPS, i18n.USERS]);
});
it('sets the dropdown to full width', () => {
expect(findDropdownAttributes('block')).toBeUndefined();
wrapper = createComponent({ fullWidth: true });
expect(findDropdownAttributes('block')).not.toBeUndefined();
expect(findDropdownAttributes('block')).toBe('true');
});
describe('with a selected namespace', () => {
const selectedGroupIndex = 1;
const selectedItem = group[selectedGroupIndex];
beforeEach(() => {
findDropdownItems().at(selectedGroupIndex).vm.$emit('click');
});
it('sets the dropdown text', () => {
expect(selectedDropdownItemText()).toBe(selectedItem.humanName);
});
it('emits the `select` event when a namespace is selected', () => {
const args = [selectedItem];
expect(wrapper.emitted('select')).toEqual([args]);
});
});
});

View File

@ -45,6 +45,39 @@ RSpec.describe NamespacesHelper do
user_group.add_owner(user)
end
describe '#namespaces_as_json' do
let(:result) { helper.namespaces_as_json(user) }
before do
allow(helper).to receive(:current_user).and_return(user)
end
it 'returns the user\'s groups' do
json_data = Gitlab::Json.parse(result)
expect(result).to include('group')
expect(json_data['group']).to include(
"id" => user_group.id,
"name" => user_group.name,
"display_path" => user_group.full_path,
"human_name" => user_group.human_name
)
end
it 'returns the user\'s namespace' do
user_namespace = user.namespace
json_data = Gitlab::Json.parse(result)
expect(result).to include('user')
expect(json_data['user']).to include(
"id" => user_namespace.id,
"name" => user_namespace.name,
"display_path" => user_namespace.full_path,
"human_name" => user_namespace.human_name
)
end
end
describe '#namespaces_options' do
context 'when admin mode is enabled', :enable_admin_mode do
it 'returns groups without being a member for admin' do

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true
require "fast_spec_helper"
require "support/graphql/fake_query_type"
require "spec_helper"
RSpec.describe Gitlab::Graphql::Tracers::LoggerTracer do
let(:dummy_schema) do
@ -49,4 +48,15 @@ RSpec.describe Gitlab::Graphql::Tracers::LoggerTracer do
dummy_schema.execute(query_string, variables: variables)
end
it 'logs exceptions for breaking queries' do
query_string = "query fooOperation { breakingField }"
expect(::Gitlab::GraphqlLogger).to receive(:info).with(a_hash_including({
'exception.message' => 'This field is supposed to break',
'exception.class' => 'RuntimeError'
}))
expect { dummy_schema.execute(query_string) }.to raise_error(/This field is supposed to break/)
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'spec_helper'
require 'rspec-parameterized'
require "support/graphql/fake_query_type"
@ -36,7 +36,7 @@ RSpec.describe Gitlab::Graphql::Tracers::MetricsTracer do
end
with_them do
it 'increments sli' do
it 'increments apdex sli' do
# Trigger initialization
fake_schema
@ -56,5 +56,13 @@ RSpec.describe Gitlab::Graphql::Tracers::MetricsTracer do
fake_schema.execute("query lorem { helloWorld }")
end
end
it "does not record apdex for failing queries" do
query_string = "query fooOperation { breakingField }"
expect(Gitlab::Metrics::RailsSlis.graphql_query_apdex).not_to receive(:increment)
expect { fake_schema.execute(query_string) }.to raise_error(/This field is supposed to break/)
end
end
end

View File

@ -20,6 +20,7 @@ RSpec.describe Gitlab::Graphql::Tracers::TimerTracer do
before do
current_time = 0
allow(tracer_spy).to receive(:trace)
allow(Gitlab::Metrics::System).to receive(:monotonic_time) do
current_time += expected_duration
end
@ -30,6 +31,18 @@ RSpec.describe Gitlab::Graphql::Tracers::TimerTracer do
dummy_schema.execute(query_string)
expect_to_have_traced(tracer_spy, expected_duration, query_string)
end
it "adds a duration_s even if the query failed" do
query_string = "query fooOperation { breakingField }"
expect { dummy_schema.execute(query_string) }.to raise_error(/This field is supposed to break/)
expect_to_have_traced(tracer_spy, expected_duration, query_string)
end
def expect_to_have_traced(tracer_spy, expected_duration, query_string)
# "parse" and "execute_query" are just arbitrary trace events
expect(tracer_spy).to have_received(:trace).with("parse", {
duration_s: expected_duration,

View File

@ -25,6 +25,28 @@ RSpec.describe LfsObjectsProject do
end
end
describe '#link_to_project!' do
it 'does not throw error when duplicate exists' do
subject
expect do
result = described_class.link_to_project!(subject.lfs_object, subject.project)
expect(result).to be_a(LfsObjectsProject)
end.not_to change { described_class.count }
end
it 'upserts a new entry and updates the project cache' do
new_project = create(:project)
allow(ProjectCacheWorker).to receive(:perform_async).and_call_original
expect(ProjectCacheWorker).to receive(:perform_async).with(new_project.id, [], [:lfs_objects_size])
expect { described_class.link_to_project!(subject.lfs_object, new_project) }
.to change { described_class.count }
expect(described_class.find_by(lfs_object_id: subject.lfs_object.id, project_id: new_project.id)).to be_present
end
end
describe '#update_project_statistics' do
it 'updates project statistics when the object is added' do
expect(ProjectCacheWorker).to receive(:perform_async)

View File

@ -3581,6 +3581,29 @@ RSpec.describe Project, factory_default: :keep do
expect(project.forks).to contain_exactly(forked_project)
end
end
describe '#lfs_object_oids_from_fork_source' do
let_it_be(:lfs_object) { create(:lfs_object) }
let_it_be(:another_lfs_object) { create(:lfs_object) }
let(:oids) { [lfs_object.oid, another_lfs_object.oid] }
context 'when fork has one of two LFS objects' do
before do
create(:lfs_objects_project, lfs_object: lfs_object, project: project)
create(:lfs_objects_project, lfs_object: another_lfs_object, project: forked_project)
end
it 'returns OIDs of owned LFS objects', :aggregate_failures do
expect(forked_project.lfs_objects_oids_from_fork_source(oids: oids)).to eq([lfs_object.oid])
expect(forked_project.lfs_objects_oids(oids: oids)).to eq([another_lfs_object.oid])
end
it 'returns empty when project is not a fork' do
expect(project.lfs_objects_oids_from_fork_source(oids: oids)).to eq([])
end
end
end
end
it_behaves_like 'can housekeep repository' do

View File

@ -518,13 +518,43 @@ RSpec.describe 'Git LFS API and storage' do
end
context 'in source of fork project' do
let(:other_project) { create(:project, :empty_repo) }
let(:project) { fork_project(other_project) }
before do
lfs_object.update!(projects: [other_project])
end
it_behaves_like 'batch upload with existing LFS object'
context 'when user has access to both the parent and fork' do
before do
project.add_developer(user)
other_project.add_developer(user)
end
it 'links existing LFS objects to other project' do
expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first).to include(sample_object)
expect(json_response['objects'].first).not_to have_key('actions')
expect(lfs_object.reload.projects.pluck(:id)).to match_array([other_project.id, project.id])
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(lfs_auto_link_fork_source: false)
end
it_behaves_like 'batch upload with existing LFS object'
end
end
context 'when user does not have access to parent' do
before do
project.add_developer(user)
end
it_behaves_like 'batch upload with existing LFS object'
end
end
end

View File

@ -63,6 +63,8 @@ RSpec.describe Groups::UpdateSharedRunnersService do
let_it_be(:pending_build_2) { create(:ci_pending_build, project: project, instance_runners_enabled: false) }
it 'updates pending builds for the group' do
expect(::Ci::UpdatePendingBuildService).to receive(:new).and_call_original
subject
expect(pending_build_1.reload.instance_runners_enabled).to be_truthy
@ -73,6 +75,8 @@ RSpec.describe Groups::UpdateSharedRunnersService do
let(:params) { { shared_runners_setting: 'invalid_enabled' } }
it 'does not update pending builds for the group' do
expect(::Ci::UpdatePendingBuildService).not_to receive(:new).and_call_original
subject
expect(pending_build_1.reload.instance_runners_enabled).to be_falsey
@ -99,6 +103,8 @@ RSpec.describe Groups::UpdateSharedRunnersService do
let_it_be(:pending_build_2) { create(:ci_pending_build, project: project, instance_runners_enabled: true) }
it 'updates pending builds for the group' do
expect(::Ci::UpdatePendingBuildService).to receive(:new).and_call_original
subject
expect(pending_build_1.reload.instance_runners_enabled).to be_falsey

View File

@ -1,15 +1,22 @@
# frozen_string_literal: true
require 'graphql'
module Graphql
class FakeQueryType < Types::BaseObject
class FakeQueryType < ::GraphQL::Schema::Object
graphql_name 'FakeQuery'
field :hello_world, String, null: true do
argument :message, String, required: false
end
field :breaking_field, String, null: true
def hello_world(message: "world")
"Hello #{message}!"
end
def breaking_field
raise "This field is supposed to break"
end
end
end