Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-02-17 15:18:08 +00:00
parent 70c5d79282
commit 79d6dbbd46
31 changed files with 221 additions and 325 deletions

View File

@ -1 +1 @@
4ac6a5906d27098bf0f6fb9e19c190ea9722c70a
5f39869b69abb55d5472140f0b730016f78887ed

View File

@ -65,6 +65,6 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
target_path
broadcast_type
dismissable
), target_access_levels: []).reverse_merge!(target_access_levels: [])
))
end
end

View File

@ -38,7 +38,7 @@ class Import::GitlabProjectsController < Import::BaseController
def project_params
params.permit(
:path, :namespace_id, :file
:name, :path, :namespace_id, :file
)
end

View File

@ -28,6 +28,7 @@ class Projects::CompareController < Projects::ApplicationController
COMMIT_DIFFS_PER_PAGE = 20
def index
compare_params
end
def show
@ -44,9 +45,9 @@ class Projects::CompareController < Projects::ApplicationController
def create
from_to_vars = {
from: params[:from].presence,
to: params[:to].presence,
from_project_id: params[:from_project_id].presence
from: compare_params[:from].presence,
to: compare_params[:to].presence,
from_project_id: compare_params[:from_project_id].presence
}
if from_to_vars[:from].blank? || from_to_vars[:to].blank?
@ -87,10 +88,10 @@ class Projects::CompareController < Projects::ApplicationController
# target == start_ref == from
def target_project
strong_memoize(:target_project) do
next source_project unless params.key?(:from_project_id)
next source_project if params[:from_project_id].to_i == source_project.id
next source_project unless compare_params.key?(:from_project_id)
next source_project if compare_params[:from_project_id].to_i == source_project.id
target_project = target_projects(source_project).find_by_id(params[:from_project_id])
target_project = target_projects(source_project).find_by_id(compare_params[:from_project_id])
# Just ignore the field if it points at a non-existent or hidden project
next source_project unless target_project && can?(current_user, :download_code, target_project)
@ -111,13 +112,13 @@ class Projects::CompareController < Projects::ApplicationController
end
def start_ref
@start_ref ||= Addressable::URI.unescape(params[:from])
@start_ref ||= Addressable::URI.unescape(compare_params[:from])
end
def head_ref
return @ref if defined?(@ref)
@ref = @head_ref = Addressable::URI.unescape(params[:to])
@ref = @head_ref = Addressable::URI.unescape(compare_params[:to])
end
def define_commits
@ -146,4 +147,8 @@ class Projects::CompareController < Projects::ApplicationController
.find_by(source_project: source_project, source_branch: head_ref, target_branch: start_ref)
end
# rubocop: enable CodeReuse/ActiveRecord
def compare_params
@compare_params ||= params.permit(:from, :to, :from_project_id)
end
end

View File

@ -1,22 +1,14 @@
# frozen_string_literal: true
module BroadcastMessagesHelper
include Gitlab::Utils::StrongMemoize
def current_broadcast_banner_messages
BroadcastMessage.current_banner_messages(
current_path: request.path,
user_access_level: current_user_access_level_for_project_or_group
).select do |message|
BroadcastMessage.current_banner_messages(request.path).select do |message|
cookies["hide_broadcast_message_#{message.id}"].blank?
end
end
def current_broadcast_notification_message
not_hidden_messages = BroadcastMessage.current_notification_messages(
current_path: request.path,
user_access_level: current_user_access_level_for_project_or_group
).select do |message|
not_hidden_messages = BroadcastMessage.current_notification_messages(request.path).select do |message|
cookies["hide_broadcast_message_#{message.id}"].blank?
end
not_hidden_messages.last
@ -69,31 +61,4 @@ module BroadcastMessagesHelper
def broadcast_type_options
BroadcastMessage.broadcast_types.keys.map { |w| [w.humanize, w] }
end
def target_access_level_options
BroadcastMessage::ALLOWED_TARGET_ACCESS_LEVELS.map do |access_level|
[Gitlab::Access.human_access(access_level), access_level]
end
end
def target_access_levels_display(access_levels)
access_levels.map do |access_level|
Gitlab::Access.human_access(access_level)
end.join(', ')
end
private
def current_user_access_level_for_project_or_group
return if Feature.disabled?(:role_targeted_broadcast_messages, default_enabled: :yaml)
return unless current_user.present?
strong_memoize(:current_user_access_level_for_project_or_group) do
if controller.is_a? Projects::ApplicationController
@project&.team&.max_member_access(current_user.id)
elsif controller.is_a? Groups::ApplicationController
@group&.max_member_access_for_user(current_user)
end
end
end
end

View File

@ -4,21 +4,12 @@ class BroadcastMessage < ApplicationRecord
include CacheMarkdownField
include Sortable
ALLOWED_TARGET_ACCESS_LEVELS = [
Gitlab::Access::GUEST,
Gitlab::Access::REPORTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::MAINTAINER,
Gitlab::Access::OWNER
].freeze
cache_markdown_field :message, pipeline: :broadcast_message, whitelisted: true
validates :message, presence: true
validates :starts_at, presence: true
validates :ends_at, presence: true
validates :broadcast_type, presence: true
validates :target_access_levels, inclusion: { in: ALLOWED_TARGET_ACCESS_LEVELS }
validates :color, allow_blank: true, color: true
validates :font, allow_blank: true, color: true
@ -38,20 +29,20 @@ class BroadcastMessage < ApplicationRecord
}
class << self
def current_banner_messages(current_path: nil, user_access_level: nil)
fetch_messages BANNER_CACHE_KEY, current_path, user_access_level do
def current_banner_messages(current_path = nil)
fetch_messages BANNER_CACHE_KEY, current_path do
current_and_future_messages.banner
end
end
def current_notification_messages(current_path: nil, user_access_level: nil)
fetch_messages NOTIFICATION_CACHE_KEY, current_path, user_access_level do
def current_notification_messages(current_path = nil)
fetch_messages NOTIFICATION_CACHE_KEY, current_path do
current_and_future_messages.notification
end
end
def current(current_path: nil, user_access_level: nil)
fetch_messages CACHE_KEY, current_path, user_access_level do
def current(current_path = nil)
fetch_messages CACHE_KEY, current_path do
current_and_future_messages
end
end
@ -72,7 +63,7 @@ class BroadcastMessage < ApplicationRecord
private
def fetch_messages(cache_key, current_path, user_access_level)
def fetch_messages(cache_key, current_path)
messages = cache.fetch(cache_key, as: BroadcastMessage, expires_in: cache_expires_in) do
yield
end
@ -83,13 +74,7 @@ class BroadcastMessage < ApplicationRecord
# displaying we'll refresh the cache so we don't need to keep filtering.
cache.expire(cache_key) if now_or_future != messages
messages = now_or_future.select(&:now?)
messages = messages.select do |message|
message.matches_current_user_access_level?(user_access_level)
end
messages.select do |message|
message.matches_current_path(current_path)
end
now_or_future.select(&:now?).select { |message| message.matches_current_path(current_path) }
end
end
@ -117,12 +102,6 @@ class BroadcastMessage < ApplicationRecord
now? || future?
end
def matches_current_user_access_level?(user_access_level)
return true if target_access_levels.empty?
target_access_levels.include? user_access_level
end
def matches_current_path(current_path)
return false if current_path.blank? && target_path.present?
return true if current_path.blank? || target_path.blank?

View File

@ -882,6 +882,7 @@ class Group < Namespace
.where(group_member_table[:requested_at].eq(nil))
.where(group_member_table[:source_id].eq(group_group_link_table[:shared_with_group_id]))
.where(group_member_table[:source_type].eq('Namespace'))
.where(group_member_table[:state].eq(::Member::STATE_ACTIVE))
.non_minimal_access
end

View File

@ -2,6 +2,10 @@
module Clusters
class ClusterPresenter < Gitlab::View::Presenter::Delegated
include ::Gitlab::Utils::StrongMemoize
delegator_override_with ::Gitlab::Utils::StrongMemoize # This module inclusion is expected. See https://gitlab.com/gitlab-org/gitlab/-/issues/352884.
presents ::Clusters::Cluster, as: :cluster
def provider_label

View File

@ -6,6 +6,9 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
include MarkupHelper
include TreeHelper
include ChecksCollaboration
include Gitlab::Utils::StrongMemoize
delegator_override_with Gitlab::Utils::StrongMemoize # This module inclusion is expected. See https://gitlab.com/gitlab-org/gitlab/-/issues/352884.
APPROVALS_WIDGET_BASE_TYPE = 'base'

View File

@ -86,7 +86,7 @@ class PostReceiveService
banner = nil
if project
scoped_messages = BroadcastMessage.current_banner_messages(current_path: project.full_path).select do |message|
scoped_messages = BroadcastMessage.current_banner_messages(project.full_path).select do |message|
message.target_path.present? && message.matches_current_path(project.full_path)
end

View File

@ -55,14 +55,6 @@
= f.check_box :dismissable
= f.label :dismissable do
= _('Allow users to dismiss the broadcast message')
- if Feature.enabled?(:role_targeted_broadcast_messages, default_enabled: :yaml)
.form-group.row
.col-sm-2.col-form-label
= f.label :target_access_levels, _('Target roles')
.col-sm-10
= f.select :target_access_levels, target_access_level_options, { include_hidden: false }, multiple: true, class: 'form-control'
.form-text.text-muted
= _('The broadcast message displays only to users in projects and groups who have these roles.')
.form-group.row.js-toggle-colors-container.toggle-colors.hide
.col-sm-2.col-form-label
= f.label :font, _("Font Color")

View File

@ -1,11 +1,10 @@
- breadcrumb_title _("Messages")
- page_title _("Broadcast Messages")
- targeted_broadcast_messages_enabled = Feature.enabled?(:role_targeted_broadcast_messages, default_enabled: :yaml)
%h3.page-title
= _('Broadcast Messages')
%p.light
= _('Use banners and notifications to notify your users about scheduled maintenance, recent upgrades, and more.')
= _('Broadcast messages are displayed for every user and can be used to notify users about scheduled maintenance, recent upgrades and more.')
= render 'form'
@ -20,10 +19,8 @@
%th= _('Preview')
%th= _('Starts')
%th= _('Ends')
- if targeted_broadcast_messages_enabled
%th= _('Target roles')
%th= _('Target Path')
%th= _('Type')
%th= _(' Target Path')
%th= _(' Type')
%th &nbsp;
%tbody
- @broadcast_messages.each do |message|
@ -36,9 +33,6 @@
= message.starts_at
%td
= message.ends_at
- if targeted_broadcast_messages_enabled
%td
= target_access_levels_display(message.target_access_levels)
%td
= message.target_path
%td

View File

@ -13,4 +13,4 @@
= html_escape(_("Changes are shown as if the %{b_open}source%{b_close} revision was being merged into the %{b_open}target%{b_close} revision.")) % { b_open: '<b>'.html_safe, b_close: '</b>'.html_safe }
.prepend-top-20
#js-compare-selector{ data: project_compare_selector_data(@project, @merge_request, params) }
#js-compare-selector{ data: project_compare_selector_data(@project, @merge_request, @compare_params) }

View File

@ -1,8 +0,0 @@
---
name: role_targeted_broadcast_messages
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77498
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351736
milestone: '14.8'
type: development
group: group::activation
default_enabled: false

View File

@ -1,7 +0,0 @@
# frozen_string_literal: true
class AddTargetAccessLevelsToBroadcastMessages < Gitlab::Database::Migration[1.0]
def change
add_column :broadcast_messages, :target_access_levels, :integer, array: true, null: false, default: []
end
end

View File

@ -1 +0,0 @@
6e273d5b92595ae6054b0665b4ff446fb2bed24ff1aab122537833dc8f4d9ab8

View File

@ -11364,8 +11364,7 @@ CREATE TABLE broadcast_messages (
cached_markdown_version integer,
target_path character varying(255),
broadcast_type smallint DEFAULT 1 NOT NULL,
dismissable boolean,
target_access_levels integer[] DEFAULT '{}'::integer[] NOT NULL
dismissable boolean
);
CREATE SEQUENCE broadcast_messages_id_seq

View File

@ -8656,6 +8656,18 @@ Describes a rule for who can approve merge requests.
| <a id="approvalruletype"></a>`type` | [`ApprovalRuleType`](#approvalruletype) | Type of the rule. |
| <a id="approvalruleusers"></a>`users` | [`UserCoreConnection`](#usercoreconnection) | List of users added as approvers for the rule. (see [Connections](#connections)) |
### `AssetType`
Represents a vulnerability asset type.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="assettypename"></a>`name` | [`String!`](#string) | Name of the asset. |
| <a id="assettypetype"></a>`type` | [`String!`](#string) | Type of the asset. |
| <a id="assettypeurl"></a>`url` | [`String!`](#string) | URL of the asset. |
### `AwardEmoji`
An emoji awarded by a user.
@ -13475,10 +13487,13 @@ Represents vulnerability finding of a security report on the pipeline.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="pipelinesecurityreportfindingassets"></a>`assets` | [`[AssetType!]`](#assettype) | List of assets associated with the vulnerability. |
| <a id="pipelinesecurityreportfindingconfidence"></a>`confidence` | [`String`](#string) | Type of the security report that found the vulnerability. |
| <a id="pipelinesecurityreportfindingdescription"></a>`description` | [`String`](#string) | Description of the vulnerability finding. |
| <a id="pipelinesecurityreportfindingevidence"></a>`evidence` | [`VulnerabilityEvidence`](#vulnerabilityevidence) | Evidence for the vulnerability. |
| <a id="pipelinesecurityreportfindingfalsepositive"></a>`falsePositive` | [`Boolean`](#boolean) | Indicates whether the vulnerability is a false positive. |
| <a id="pipelinesecurityreportfindingidentifiers"></a>`identifiers` | [`[VulnerabilityIdentifier!]!`](#vulnerabilityidentifier) | Identifiers of the vulnerabilit finding. |
| <a id="pipelinesecurityreportfindingidentifiers"></a>`identifiers` | [`[VulnerabilityIdentifier!]!`](#vulnerabilityidentifier) | Identifiers of the vulnerability finding. |
| <a id="pipelinesecurityreportfindinglinks"></a>`links` | [`[VulnerabilityLink!]`](#vulnerabilitylink) | List of links associated with the vulnerability. |
| <a id="pipelinesecurityreportfindinglocation"></a>`location` | [`VulnerabilityLocation`](#vulnerabilitylocation) | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability. |
| <a id="pipelinesecurityreportfindingname"></a>`name` | [`String`](#string) | Name of the vulnerability finding. |
| <a id="pipelinesecurityreportfindingproject"></a>`project` | [`Project`](#project) | Project on which the vulnerability finding was found. |
@ -13488,6 +13503,7 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="pipelinesecurityreportfindingseverity"></a>`severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability finding. |
| <a id="pipelinesecurityreportfindingsolution"></a>`solution` | [`String`](#string) | URL to the vulnerability's details page. |
| <a id="pipelinesecurityreportfindingstate"></a>`state` | [`VulnerabilityState`](#vulnerabilitystate) | Finding status. |
| <a id="pipelinesecurityreportfindingtitle"></a>`title` | [`String`](#string) | Title of the vulnerability finding. |
| <a id="pipelinesecurityreportfindinguuid"></a>`uuid` | [`String`](#string) | Name of the vulnerability finding. |
### `Project`
@ -16348,6 +16364,44 @@ Represents the vulnerability details URL field.
| <a id="vulnerabilitydetailurlname"></a>`name` | [`String`](#string) | Name of the field. |
| <a id="vulnerabilitydetailurltext"></a>`text` | [`String`](#string) | Text of the URL. |
### `VulnerabilityEvidence`
Represents a Vulnerability Evidence.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilityevidencerequest"></a>`request` | [`VulnerabilityRequest`](#vulnerabilityrequest) | HTTP request of the Vulnerability Evidence. |
| <a id="vulnerabilityevidenceresponse"></a>`response` | [`VulnerabilityResponse`](#vulnerabilityresponse) | HTTP response of the Vulnerability Evidence. |
| <a id="vulnerabilityevidencesource"></a>`source` | [`VulnerabilityEvidenceSource`](#vulnerabilityevidencesource) | Source of the Vulnerability Evidence. |
| <a id="vulnerabilityevidencesummary"></a>`summary` | [`String`](#string) | Summary of the Vulnerability Evidence. |
| <a id="vulnerabilityevidencesupportingmessages"></a>`supportingMessages` | [`[VulnerabilityEvidenceSupportingMessage!]`](#vulnerabilityevidencesupportingmessage) | Supporting messages of the Vulnerability Evidence. |
### `VulnerabilityEvidenceSource`
Represents a vulnerability evidence.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilityevidencesourceidentifier"></a>`identifier` | [`String!`](#string) | ID of the Vulnerability Evidence Source. |
| <a id="vulnerabilityevidencesourcename"></a>`name` | [`String!`](#string) | Name of the Vulnerability Evidence Source. |
| <a id="vulnerabilityevidencesourceurl"></a>`url` | [`String`](#string) | URL of the Vulnerability Evidence Source. |
### `VulnerabilityEvidenceSupportingMessage`
Represents a vulnerability evidence supporting message.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilityevidencesupportingmessagename"></a>`name` | [`String!`](#string) | Name of the vulnerability supporting message. |
| <a id="vulnerabilityevidencesupportingmessagerequest"></a>`request` | [`VulnerabilityRequest`](#vulnerabilityrequest) | HTTP request of the vulnerability evidence supporting message. |
| <a id="vulnerabilityevidencesupportingmessageresponse"></a>`response` | [`VulnerabilityResponse`](#vulnerabilityresponse) | HTTP response of the vulnerability evidence supporting message. |
### `VulnerabilityExternalIssueLink`
Represents an external issue link of a vulnerability.
@ -16430,8 +16484,11 @@ Represents the location of a vulnerability found by a Coverage Fuzzing scan.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilitylocationcoveragefuzzingblobpath"></a>`blobPath` | [`String`](#string) | Blob path to the vulnerable file. |
| <a id="vulnerabilitylocationcoveragefuzzingcrashaddress"></a>`crashAddress` | [`String`](#string) | Relative address in memory were the crash occurred. |
| <a id="vulnerabilitylocationcoveragefuzzingcrashtype"></a>`crashType` | [`String`](#string) | Type of the crash. |
| <a id="vulnerabilitylocationcoveragefuzzingendline"></a>`endLine` | [`String`](#string) | Number of the last relevant line in the vulnerable file. |
| <a id="vulnerabilitylocationcoveragefuzzingfile"></a>`file` | [`String`](#string) | Path to the vulnerable file. |
| <a id="vulnerabilitylocationcoveragefuzzingstacktracesnippet"></a>`stacktraceSnippet` | [`String`](#string) | Stack trace recorded during fuzzing resulting the crash. |
| <a id="vulnerabilitylocationcoveragefuzzingstartline"></a>`startLine` | [`String`](#string) | Number of the first relevant line in the vulnerable file. |
| <a id="vulnerabilitylocationcoveragefuzzingvulnerableclass"></a>`vulnerableClass` | [`String`](#string) | Class containing the vulnerability. |
| <a id="vulnerabilitylocationcoveragefuzzingvulnerablemethod"></a>`vulnerableMethod` | [`String`](#string) | Method containing the vulnerability. |
@ -16519,6 +16576,43 @@ Check permissions for the current user on a vulnerability.
| <a id="vulnerabilitypermissionsreadvulnerabilityfeedback"></a>`readVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `read_vulnerability_feedback` on this resource. |
| <a id="vulnerabilitypermissionsupdatevulnerabilityfeedback"></a>`updateVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `update_vulnerability_feedback` on this resource. |
### `VulnerabilityRequest`
Represents a Vulnerability Request.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilityrequestbody"></a>`body` | [`String`](#string) | Body of the Vulnerability Request. |
| <a id="vulnerabilityrequestheaders"></a>`headers` | [`[VulnerabilityRequestResponseHeader!]!`](#vulnerabilityrequestresponseheader) | HTTP headers of the Vulnerability Request. |
| <a id="vulnerabilityrequestmethod"></a>`method` | [`String`](#string) | Method of the Vulnerability Request. |
| <a id="vulnerabilityrequesturl"></a>`url` | [`String`](#string) | URL of the Vulnerability Request. |
### `VulnerabilityRequestResponseHeader`
Represents a Vulnerability Request/Response Header.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilityrequestresponseheadername"></a>`name` | [`String`](#string) | Name of the Vulnerability Request/Response Header. |
| <a id="vulnerabilityrequestresponseheadervalue"></a>`value` | [`String`](#string) | Value of the Vulnerability Request/Response Header. |
### `VulnerabilityResponse`
Represents a Vulnerability Response.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilityresponsebody"></a>`body` | [`String`](#string) | Body of the Vulnerability Response. |
| <a id="vulnerabilityresponseheaders"></a>`headers` | [`[VulnerabilityRequestResponseHeader!]!`](#vulnerabilityrequestresponseheader) | HTTP headers of the Vulnerability Response. |
| <a id="vulnerabilityresponsereasonphrase"></a>`reasonPhrase` | [`String`](#string) | Reason Phrase of the Vulnerability Response. |
| <a id="vulnerabilityresponsestatuscode"></a>`statusCode` | [`Int`](#int) | Status Code of the Vulnerability Response. |
### `VulnerabilityScanner`
Represents a vulnerability scanner.

View File

@ -89,7 +89,7 @@ Example responses:
The CI lint returns an expanded version of the configuration. The expansion does not
work for CI configuration added with [`include: local`](../ci/yaml/index.md#includelocal),
or with [`extends:`](../ci/yaml/index.md#extends).
and the [`extends:`](../ci/yaml/index.md#extends) keyword is [not fully supported](https://gitlab.com/gitlab-org/gitlab/-/issues/258843).
Example contents of a `.gitlab-ci.yml` passed to the CI Lint API with
`include_merged_yaml` and `include_jobs` set as true:

View File

@ -324,7 +324,15 @@ lein cloverage | perl -pe 's/\e\[?.*?[\@-~]//g'
Pipeline badges indicate the pipeline status and a test coverage value
for your project. These badges are determined by the latest successful pipeline.
### View the code for the pipeline status and coverage reports badges
## Latest release badge
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33368) in GitLab 14.8.
A latest release badge indicates the latest release tag name for your project.
By default, the badge fetches the release sorted using the [`released_at`](../../api/releases/index.md#create-a-release) time.
Support for [`semver`](https://semver.org/) sorting is tracked [in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/352945).
### View the code for the pipeline status, coverage reports, and latest release badges
You can view the exact link for your badges. Then you can embed the badge in your HTML
or Markdown pages.
@ -332,7 +340,7 @@ or Markdown pages.
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. In the **Pipeline status** or **Coverage report** sections, view the URLs for the images.
1. In the **Pipeline status**, **Coverage report**, or **Latest release** sections, view the URLs for the images.
![Pipelines badges](img/pipelines_settings_badges.png)
@ -406,6 +414,25 @@ If an invalid boundary is set, GitLab automatically adjusts it to be valid. For
if `min_good` is set `80`, and `min_acceptable` is set to `85` (too high), GitLab automatically
sets `min_acceptable` to `79` (`min_good` - `1`).
### Latest release badge
When a release exists in your project, it shows the latest release tag name. If there is no release,
it shows `none`.
You can access a latest release badge image by using the following link:
```plaintext
https://gitlab.example.com/<namespace>/<project>/-/badges/release.svg
```
#### Sorting preferences
By default, the latest release badge fetches the release using `release_at` time. The use of the query parameter `?order_by=release_at` is optional, and support for `?order_by=semver` is tracked [in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/352945):
```plaintext
https://gitlab.example.com/<namespace>/<project>/-/badges/release.svg?order_by=release_at
```
### Badge styles
Pipeline badges can be rendered in different styles by adding the `style=style_name` parameter to the URL. Two styles are available:

View File

@ -399,7 +399,7 @@ migrations:
1. Change the index pattern to `pubsub-sidekiq-inf-gprd*`.
1. Add filter for `json.queue: cronjob:database_batched_background_migration`.
#### PostgerSQL slow queries log
#### PostgreSQL slow queries log
Slow queries log keeps track of low queries that took above 1 second to execute. To see them
for batched background migration:

View File

@ -125,6 +125,14 @@ it fails with this error as `/` is not a valid character in a project name.
A project with that name already exists.
##### `Exception: Error importing repository into (namespace) - No space left on device`
The disk has insufficient space to complete the import.
During import, the tarball is cached in your configured `shared_path` directory. Verify the
disk has enough free space to accommodate both the cached tarball and the unpacked
project files on disk.
### Importing via the Rails console
The last option is to import a project using a Rails console:

View File

@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Badges are a unified way to present condensed pieces of information about your
projects. They consist of a small image and a URL that the image
points to. Examples for badges can be the [pipeline status](../../ci/pipelines/settings.md#pipeline-status-badge),
[test coverage](../../ci/pipelines/settings.md#test-coverage-report-badge), or ways to contact the
[test coverage](../../ci/pipelines/settings.md#test-coverage-report-badge), [latest release](../../ci/pipelines/settings.md#latest-release-badge), or ways to contact the
project maintainers.
![Badges on Project information page](img/project_overview_badges_v13_10.png)

View File

@ -28,9 +28,15 @@ msgstr ""
msgid " Please sign in."
msgstr ""
msgid " Target Path"
msgstr ""
msgid " Try to %{action} this file again."
msgstr ""
msgid " Type"
msgstr ""
msgid " You need to do this before %{grace_period_deadline}."
msgstr ""
@ -6130,6 +6136,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
msgid "Broadcast messages are displayed for every user and can be used to notify users about scheduled maintenance, recent upgrades and more."
msgstr ""
msgid "Browse Directory"
msgstr ""
@ -35808,9 +35817,6 @@ msgstr ""
msgid "Target branch"
msgstr ""
msgid "Target roles"
msgstr ""
msgid "Target-Branch"
msgstr ""
@ -36299,9 +36305,6 @@ msgstr ""
msgid "The branch or tag does not exist"
msgstr ""
msgid "The broadcast message displays only to users in projects and groups who have these roles."
msgstr ""
msgid "The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git."
msgstr ""
@ -39547,9 +39550,6 @@ msgstr ""
msgid "Use authorized_keys file to authenticate SSH keys"
msgstr ""
msgid "Use banners and notifications to notify your users about scheduled maintenance, recent upgrades, and more."
msgstr ""
msgid "Use cURL"
msgstr ""

View File

@ -25,15 +25,25 @@ RSpec.describe Projects::CompareController do
end
describe 'GET index' do
let(:params) { { namespace_id: project.namespace, project_id: project } }
render_views
before do
get :index, params: { namespace_id: project.namespace, project_id: project }
get :index, params: params
end
it 'returns successfully' do
expect(response).to be_successful
end
context 'with incorrect parameters' do
let(:params) { super().merge(from: { invalid: :param }, to: { also: :invalid }) }
it 'returns successfully' do
expect(response).to be_successful
end
end
end
describe 'GET show' do
@ -340,12 +350,13 @@ RSpec.describe Projects::CompareController do
context 'when sending invalid params' do
where(:from_ref, :to_ref, :from_project_id, :expected_redirect_params) do
'' | '' | '' | {}
'main' | '' | '' | { from: 'main' }
'' | 'main' | '' | { to: 'main' }
'' | '' | '1' | { from_project_id: 1 }
'main' | '' | '1' | { from: 'main', from_project_id: 1 }
'' | 'main' | '1' | { to: 'main', from_project_id: 1 }
'' | '' | '' | {}
'main' | '' | '' | { from: 'main' }
'' | 'main' | '' | { to: 'main' }
'' | '' | '1' | { from_project_id: 1 }
'main' | '' | '1' | { from: 'main', from_project_id: 1 }
'' | 'main' | '1' | { to: 'main', from_project_id: 1 }
['a'] | ['b'] | ['c'] | {}
end
with_them do

View File

@ -7,12 +7,7 @@ RSpec.describe 'Admin Broadcast Messages' do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
create(
:broadcast_message,
:expired,
message: 'Migration to new server',
target_access_levels: [Gitlab::Access::DEVELOPER]
)
create(:broadcast_message, :expired, message: 'Migration to new server')
visit admin_broadcast_messages_path
end
@ -26,13 +21,10 @@ RSpec.describe 'Admin Broadcast Messages' do
fill_in 'broadcast_message_target_path', with: '*/user_onboarded'
fill_in 'broadcast_message_font', with: '#b94a48'
select Date.today.next_year.year, from: 'broadcast_message_ends_at_1i'
select 'Guest', from: 'broadcast_message_target_access_levels'
select 'Owner', from: 'broadcast_message_target_access_levels'
click_button 'Add broadcast message'
expect(current_path).to eq admin_broadcast_messages_path
expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST'
expect(page).to have_content 'Guest, Owner'
expect(page).to have_content '*/user_onboarded'
expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST'
expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"])
@ -43,14 +35,10 @@ RSpec.describe 'Admin Broadcast Messages' do
fill_in 'broadcast_message_target_path', with: '*/user_onboarded'
select 'Notification', from: 'broadcast_message_broadcast_type'
select Date.today.next_year.year, from: 'broadcast_message_ends_at_1i'
select 'Reporter', from: 'broadcast_message_target_access_levels'
select 'Developer', from: 'broadcast_message_target_access_levels'
select 'Maintainer', from: 'broadcast_message_target_access_levels'
click_button 'Add broadcast message'
expect(current_path).to eq admin_broadcast_messages_path
expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST'
expect(page).to have_content 'Reporter, Developer, Maintainer'
expect(page).to have_content '*/user_onboarded'
expect(page).to have_content 'Notification'
expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST'
@ -59,15 +47,10 @@ RSpec.describe 'Admin Broadcast Messages' do
it 'edit an existing broadcast message' do
click_link 'Edit'
fill_in 'broadcast_message_message', with: 'Application update RIGHT NOW'
select 'Reporter', from: 'broadcast_message_target_access_levels'
click_button 'Update broadcast message'
expect(current_path).to eq admin_broadcast_messages_path
expect(page).to have_content 'Application update RIGHT NOW'
page.within('.table-responsive') do
expect(page).to have_content 'Reporter, Developer'
end
end
it 'remove an existing broadcast message' do

View File

@ -41,7 +41,7 @@ RSpec.describe 'Import/Export - project import integration test', :js do
project = Project.last
expect(project).not_to be_nil
expect(page).to have_content("Project 'test-project-path' is being imported")
expect(page).to have_content("Project 'Test Project Name' is being imported")
end
it 'invalid project' do

View File

@ -3,71 +3,6 @@
require 'spec_helper'
RSpec.describe BroadcastMessagesHelper do
include Gitlab::Routing.url_helpers
let_it_be(:user) { create(:user) }
before do
allow(helper).to receive(:current_user).and_return(user)
end
shared_examples 'returns role-targeted broadcast message when in project, group, or sub-group URL' do
let(:feature_flag_state) { true }
before do
stub_feature_flags(role_targeted_broadcast_messages: feature_flag_state)
allow(helper).to receive(:cookies) { {} }
end
context 'when in a project page' do
let_it_be(:project) { create(:project) }
before do
project.add_developer(user)
assign(:project, project)
allow(helper).to receive(:controller) { ProjectsController.new }
end
it { is_expected.to eq message }
context 'when feature flag is disabled' do
let(:feature_flag_state) { false }
it { is_expected.to be_nil }
end
end
context 'when in a group page' do
let_it_be(:group) { create(:group) }
before do
group.add_developer(user)
assign(:group, group)
allow(helper).to receive(:controller) { GroupsController.new }
end
it { is_expected.to eq message }
context 'when feature flag is disabled' do
let(:feature_flag_state) { false }
it { is_expected.to be_nil }
end
end
context 'when not in a project, group, or sub-group page' do
it { is_expected.to be_nil }
context 'when feature flag is disabled' do
let(:feature_flag_state) { false }
it { is_expected.to be_nil }
end
end
end
describe 'current_broadcast_notification_message' do
subject { helper.current_broadcast_notification_message }
@ -89,27 +24,17 @@ RSpec.describe BroadcastMessagesHelper do
context 'without broadcast notification messages' do
it { is_expected.to be_nil }
end
describe 'user access level targeted messages' do
let_it_be(:message) { create(:broadcast_message, broadcast_type: 'notification', starts_at: Time.now, target_access_levels: [Gitlab::Access::DEVELOPER]) }
include_examples 'returns role-targeted broadcast message when in project, group, or sub-group URL'
end
end
describe 'current_broadcast_banner_messages' do
describe 'user access level targeted messages' do
let_it_be(:message) { create(:broadcast_message, broadcast_type: 'banner', starts_at: Time.now, target_access_levels: [Gitlab::Access::DEVELOPER]) }
subject { helper.current_broadcast_banner_messages.first }
include_examples 'returns role-targeted broadcast message when in project, group, or sub-group URL'
end
end
describe 'broadcast_message' do
let_it_be(:user) { create(:user) }
let(:current_broadcast_message) { BroadcastMessage.new(message: 'Current Message') }
before do
allow(helper).to receive(:current_user).and_return(user)
end
it 'returns nil when no current message' do
expect(helper.broadcast_message(nil)).to be_nil
end

View File

@ -23,8 +23,6 @@ RSpec.describe BroadcastMessage do
it { is_expected.to allow_value(1).for(:broadcast_type) }
it { is_expected.not_to allow_value(nil).for(:broadcast_type) }
it { is_expected.not_to allow_value(nil).for(:target_access_levels) }
it { is_expected.to validate_inclusion_of(:target_access_levels).in_array(described_class::ALLOWED_TARGET_ACCESS_LEVELS) }
end
shared_examples 'time constrainted' do |broadcast_type|
@ -177,48 +175,12 @@ RSpec.describe BroadcastMessage do
end
end
shared_examples "matches with user access level" do |broadcast_type|
context 'when target_access_levels is empty' do
let_it_be(:message) { create(:broadcast_message, target_access_levels: [], broadcast_type: broadcast_type) }
it 'returns the message if user access level is not nil' do
expect(subject.call(nil, Gitlab::Access::MINIMAL_ACCESS)).to include(message)
end
it 'returns the message if user access level is nil' do
expect(subject.call(nil, nil)).to include(message)
end
end
context 'when target_access_levels is not empty' do
let_it_be(:target_access_levels) { [Gitlab::Access::GUEST] }
let_it_be(:message) { create(:broadcast_message, target_access_levels: target_access_levels, broadcast_type: broadcast_type) }
it "does not return the message if user access level is nil" do
expect(subject.call(nil, nil)).to be_empty
end
it "returns the message if user access level is in target_access_levels" do
expect(subject.call(nil, Gitlab::Access::GUEST)).to include(message)
end
it "does not return the message if user access level is not in target_access_levels" do
expect(subject.call(nil, Gitlab::Access::MINIMAL_ACCESS)).to be_empty
end
end
end
describe '.current', :use_clean_rails_memory_store_caching do
subject do
-> (path = nil, user_access_level = nil) do
described_class.current(current_path: path, user_access_level: user_access_level)
end
end
subject { -> (path = nil) { described_class.current(path) } }
it_behaves_like 'time constrainted', :banner
it_behaves_like 'message cache', :banner
it_behaves_like 'matches with current path', :banner
it_behaves_like 'matches with user access level', :banner
it 'returns both types' do
banner_message = create(:broadcast_message, broadcast_type: :banner)
@ -229,16 +191,11 @@ RSpec.describe BroadcastMessage do
end
describe '.current_banner_messages', :use_clean_rails_memory_store_caching do
subject do
-> (path = nil, user_access_level = nil) do
described_class.current_banner_messages(current_path: path, user_access_level: user_access_level)
end
end
subject { -> (path = nil) { described_class.current_banner_messages(path) } }
it_behaves_like 'time constrainted', :banner
it_behaves_like 'message cache', :banner
it_behaves_like 'matches with current path', :banner
it_behaves_like 'matches with user access level', :banner
it 'only returns banners' do
banner_message = create(:broadcast_message, broadcast_type: :banner)
@ -249,16 +206,11 @@ RSpec.describe BroadcastMessage do
end
describe '.current_notification_messages', :use_clean_rails_memory_store_caching do
subject do
-> (path = nil, user_access_level = nil) do
described_class.current_notification_messages(current_path: path, user_access_level: user_access_level)
end
end
subject { -> (path = nil) { described_class.current_notification_messages(path) } }
it_behaves_like 'time constrainted', :notification
it_behaves_like 'message cache', :notification
it_behaves_like 'matches with current path', :notification
it_behaves_like 'matches with user access level', :notification
it 'only returns notifications' do
notification_message = create(:broadcast_message, broadcast_type: :notification)

View File

@ -1327,10 +1327,14 @@ RSpec.describe Group do
let!(:group) { create(:group, :nested) }
let!(:maintainer) { group.parent.add_user(create(:user), GroupMember::MAINTAINER) }
let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) }
let!(:pending_maintainer) { create(:group_member, :awaiting, :maintainer, group: group.parent) }
let!(:pending_developer) { create(:group_member, :awaiting, :developer, group: group) }
it 'returns parents members' do
it 'returns parents active members' do
expect(group.members_with_parents).to include(developer)
expect(group.members_with_parents).to include(maintainer)
expect(group.members_with_parents).not_to include(pending_developer)
expect(group.members_with_parents).not_to include(pending_maintainer)
end
context 'group sharing' do
@ -1340,9 +1344,11 @@ RSpec.describe Group do
create(:group_group_link, shared_group: shared_group, shared_with_group: group)
end
it 'returns shared with group members' do
it 'returns shared with group active members' do
expect(shared_group.members_with_parents).to(
include(developer))
expect(shared_group.members_with_parents).not_to(
include(pending_developer))
end
end
end

View File

@ -1,36 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'admin/broadcast_messages/index' do
describe 'Target roles select and table column' do
let(:feature_flag_state) { true }
let_it_be(:message) { create(:broadcast_message, broadcast_type: 'banner', target_access_levels: [Gitlab::Access::GUEST, Gitlab::Access::DEVELOPER]) }
before do
assign(:broadcast_messages, BroadcastMessage.page(1))
assign(:broadcast_message, BroadcastMessage.new)
stub_feature_flags(role_targeted_broadcast_messages: feature_flag_state)
render
end
it 'rendered' do
expect(rendered).to have_content('Target roles')
expect(rendered).to have_content('Owner')
expect(rendered).to have_content('Guest, Developer')
end
context 'when feature flag is off' do
let(:feature_flag_state) { false }
it 'is not rendered' do
expect(rendered).not_to have_content('Target roles')
expect(rendered).not_to have_content('Owner')
expect(rendered).not_to have_content('Guest, Developer')
end
end
end
end