+
+
')
+ [escape_once(milestone[:title]), sidebar_milestone_remaining_days(milestone) || _('Milestone')].join('
')
end
def sidebar_milestone_remaining_days(milestone)
diff --git a/app/mailers/emails/members.rb b/app/mailers/emails/members.rb
index 06d2219d6a9..07ce9bba784 100644
--- a/app/mailers/emails/members.rb
+++ b/app/mailers/emails/members.rb
@@ -13,6 +13,8 @@ module Emails
@member_source_type = member_source_type
@member_id = member_id
+ return unless member_exists?
+
user = User.find(recipient_id)
member_email_with_layout(
@@ -24,6 +26,8 @@ module Emails
@member_source_type = member_source_type
@member_id = member_id
+ return unless member_exists?
+
member_email_with_layout(
to: member.user.notification_email_for(notification_group),
subject: subject("Access to the #{member_source.human_name} #{member_source.model_name.singular} was granted"))
@@ -45,6 +49,8 @@ module Emails
@member_id = member_id
@token = token
+ return unless member_exists?
+
member_email_with_layout(
to: member.invite_email,
subject: subject("Invitation to join the #{member_source.human_name} #{member_source.model_name.singular}"))
@@ -53,6 +59,8 @@ module Emails
def member_invite_accepted_email(member_source_type, member_id)
@member_source_type = member_source_type
@member_id = member_id
+
+ return unless member_exists?
return unless member.created_by
member_email_with_layout(
@@ -74,9 +82,11 @@ module Emails
subject: subject('Invitation declined'))
end
+ # rubocop: disable CodeReuse/ActiveRecord
def member
- @member ||= Member.find(@member_id)
+ @member ||= Member.find_by(id: @member_id)
end
+ # rubocop: enable CodeReuse/ActiveRecord
def member_source
@member_source ||= member.source
@@ -88,6 +98,11 @@ module Emails
private
+ def member_exists?
+ Gitlab::AppLogger.info("Tried to send an email invitation for a deleted group. Member id: #{@member_id}") if member.blank?
+ member.present?
+ end
+
def member_source_class
@member_source_type.classify.constantize
end
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 9f2ce09e9c0..2935ba46666 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
- VERSION = '0.19.1'
+ VERSION = '0.19.2'
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 7641b6d2a4b..874b0bc9646 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -218,6 +218,24 @@ module Clusters
provider&.status_name || connection_status.presence || :created
end
+ def connection_error
+ with_reactive_cache do |data|
+ data[:connection_error]
+ end
+ end
+
+ def node_connection_error
+ with_reactive_cache do |data|
+ data[:node_connection_error]
+ end
+ end
+
+ def metrics_connection_error
+ with_reactive_cache do |data|
+ data[:metrics_connection_error]
+ end
+ end
+
def connection_status
with_reactive_cache do |data|
data[:connection_status]
@@ -233,9 +251,7 @@ module Clusters
def calculate_reactive_cache
return unless enabled?
- gitlab_kubernetes_nodes = Gitlab::Kubernetes::Node.new(self)
-
- { connection_status: retrieve_connection_status, nodes: gitlab_kubernetes_nodes.all.presence }
+ connection_data.merge(Gitlab::Kubernetes::Node.new(self).all)
end
def persisted_applications
@@ -395,9 +411,10 @@ module Clusters
@instance_domain ||= Gitlab::CurrentSettings.auto_devops_domain
end
- def retrieve_connection_status
+ def connection_data
result = ::Gitlab::Kubernetes::KubeClient.graceful_request(id) { kubeclient.core_client.discover }
- result[:status]
+
+ { connection_status: result[:status], connection_error: result[:connection_error] }.compact
end
# To keep backward compatibility with AUTO_DEVOPS_DOMAIN
diff --git a/app/serializers/cluster_entity.rb b/app/serializers/cluster_entity.rb
index a46f2889a96..06e14179238 100644
--- a/app/serializers/cluster_entity.rb
+++ b/app/serializers/cluster_entity.rb
@@ -20,4 +20,8 @@ class ClusterEntity < Grape::Entity
expose :gitlab_managed_apps_logs_path do |cluster|
Clusters::ClusterPresenter.new(cluster, current_user: request.current_user).gitlab_managed_apps_logs_path # rubocop: disable CodeReuse/Presenter
end
+
+ expose :kubernetes_errors do |cluster|
+ ClusterErrorEntity.new(cluster)
+ end
end
diff --git a/app/serializers/cluster_error_entity.rb b/app/serializers/cluster_error_entity.rb
new file mode 100644
index 00000000000..c749537cb94
--- /dev/null
+++ b/app/serializers/cluster_error_entity.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class ClusterErrorEntity < Grape::Entity
+ expose :connection_error
+ expose :metrics_connection_error
+ expose :node_connection_error
+end
diff --git a/app/serializers/cluster_serializer.rb b/app/serializers/cluster_serializer.rb
index 92363a4942c..a70458d2bcb 100644
--- a/app/serializers/cluster_serializer.rb
+++ b/app/serializers/cluster_serializer.rb
@@ -11,6 +11,7 @@ class ClusterSerializer < BaseSerializer
:enabled,
:environment_scope,
:gitlab_managed_apps_logs_path,
+ :kubernetes_errors,
:name,
:nodes,
:path,
diff --git a/app/services/authorized_project_update/project_group_link_create_service.rb b/app/services/authorized_project_update/project_group_link_create_service.rb
index db2db091374..090b22a7820 100644
--- a/app/services/authorized_project_update/project_group_link_create_service.rb
+++ b/app/services/authorized_project_update/project_group_link_create_service.rb
@@ -6,9 +6,10 @@ module AuthorizedProjectUpdate
BATCH_SIZE = 1000
- def initialize(project, group)
+ def initialize(project, group, group_access = nil)
@project = project
@group = group
+ @group_access = group_access
end
def execute
@@ -19,19 +20,20 @@ module AuthorizedProjectUpdate
user_ids_to_delete = []
members.each do |member|
+ new_access_level = access_level(member.access_level)
existing_access_level = existing_authorizations[member.user_id]
if existing_access_level
# User might already have access to the project unrelated to the
# current project share
- next if existing_access_level >= member.access_level
+ next if existing_access_level >= new_access_level
user_ids_to_delete << member.user_id
end
authorizations_to_create << { user_id: member.user_id,
project_id: project.id,
- access_level: member.access_level }
+ access_level: new_access_level }
end
update_authorizations(user_ids_to_delete, authorizations_to_create)
@@ -42,7 +44,15 @@ module AuthorizedProjectUpdate
private
- attr_reader :project, :group
+ attr_reader :project, :group, :group_access
+
+ def access_level(membership_access_level)
+ return membership_access_level unless group_access
+
+ # access level must not be higher than the max access level set when
+ # creating the project share
+ [membership_access_level, group_access].min
+ end
def existing_project_authorizations(members)
user_ids = members.map(&:user_id)
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index 885f5c1edd0..22d7a0a99db 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -37,6 +37,7 @@ module Groups
# Overridden in EE
def post_update_hooks(updated_project_ids)
+ refresh_project_authorizations
end
def ensure_allowed_transfer
@@ -136,6 +137,16 @@ module Groups
@group.add_owner(current_user)
end
+ def refresh_project_authorizations
+ ProjectAuthorization.where(project_id: @group.all_projects.select(:id)).delete_all # rubocop: disable CodeReuse/ActiveRecord
+
+ # refresh authorized projects for current_user immediately
+ current_user.refresh_authorized_projects
+
+ # schedule refreshing projects for all the members of the group
+ @group.refresh_members_authorized_projects
+ end
+
def raise_transfer_error(message)
raise TransferError, localized_error_messages[message]
end
diff --git a/app/services/projects/group_links/create_service.rb b/app/services/projects/group_links/create_service.rb
index 3c3cab26fb5..3fcc721fe65 100644
--- a/app/services/projects/group_links/create_service.rb
+++ b/app/services/projects/group_links/create_service.rb
@@ -13,7 +13,7 @@ module Projects
)
if link.save
- setup_authorizations(group)
+ setup_authorizations(group, link.group_access)
success(link: link)
else
error(link.errors.full_messages.to_sentence, 409)
@@ -22,9 +22,10 @@ module Projects
private
- def setup_authorizations(group)
+ def setup_authorizations(group, group_access = nil)
if Feature.enabled?(:specialized_project_authorization_project_share_worker)
- AuthorizedProjectUpdate::ProjectGroupLinkCreateWorker.perform_async(project.id, group.id)
+ AuthorizedProjectUpdate::ProjectGroupLinkCreateWorker.perform_async(
+ project.id, group.id, group_access)
# AuthorizedProjectsWorker uses an exclusive lease per user but
# specialized workers might have synchronization issues. Until we
diff --git a/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json b/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
index 1154a4c45b8..cce2b28529f 100644
--- a/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
+++ b/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
@@ -15,7 +15,7 @@
"value": ""
},
{
- "field" : "SECURE_ANALYZER_IMAGE_TAG",
+ "field" : "SAST_ANALYZER_IMAGE_TAG",
"label" : "Image tag",
"type": "string",
"options": [],
diff --git a/app/workers/authorized_project_update/project_group_link_create_worker.rb b/app/workers/authorized_project_update/project_group_link_create_worker.rb
index 5fb59efaacb..dd24a9602bb 100644
--- a/app/workers/authorized_project_update/project_group_link_create_worker.rb
+++ b/app/workers/authorized_project_update/project_group_link_create_worker.rb
@@ -10,12 +10,13 @@ module AuthorizedProjectUpdate
idempotent!
- def perform(project_id, group_id)
+ def perform(project_id, group_id, group_access = nil)
project = Project.find(project_id)
group = Group.find(group_id)
- AuthorizedProjectUpdate::ProjectGroupLinkCreateService.new(project, group)
- .execute
+ AuthorizedProjectUpdate::ProjectGroupLinkCreateService
+ .new(project, group, group_access)
+ .execute
end
end
end
diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb
index 62eea8e0462..f5132459131 100644
--- a/app/workers/authorized_projects_worker.rb
+++ b/app/workers/authorized_projects_worker.rb
@@ -16,6 +16,9 @@ class AuthorizedProjectsWorker
if Rails.env.test?
def self.bulk_perform_and_wait(args_list, timeout: 10)
end
+
+ def self.bulk_perform_inline(args_list)
+ end
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/changelogs/unreleased/213289-remove-uploaded-file-call-from-lfs-storage-controller.yml b/changelogs/unreleased/213289-remove-uploaded-file-call-from-lfs-storage-controller.yml
new file mode 100644
index 00000000000..4f79d23351a
--- /dev/null
+++ b/changelogs/unreleased/213289-remove-uploaded-file-call-from-lfs-storage-controller.yml
@@ -0,0 +1,5 @@
+---
+title: Use the uploaded file set by middleware in Repositories::LfsStorageController
+merge_request: 38167
+author:
+type: changed
diff --git a/changelogs/unreleased/220303-public-snippet.yml b/changelogs/unreleased/220303-public-snippet.yml
new file mode 100644
index 00000000000..53c1da717af
--- /dev/null
+++ b/changelogs/unreleased/220303-public-snippet.yml
@@ -0,0 +1,5 @@
+---
+title: Display authored message correctly on public snippets viewed by unauthenticated users
+merge_request: 38614
+author:
+type: fixed
diff --git a/changelogs/unreleased/230734-change-stuck_block-component-to-use-glbadge.yml b/changelogs/unreleased/230734-change-stuck_block-component-to-use-glbadge.yml
new file mode 100644
index 00000000000..55dbc092802
--- /dev/null
+++ b/changelogs/unreleased/230734-change-stuck_block-component-to-use-glbadge.yml
@@ -0,0 +1,5 @@
+---
+title: Change the job stuck page to use UI library components
+merge_request: 38618
+author:
+type: changed
diff --git a/changelogs/unreleased/rc-add_dashboard_path_to_prometheus_metrics.yml b/changelogs/unreleased/rc-add_dashboard_path_to_prometheus_metrics.yml
new file mode 100644
index 00000000000..10564b87012
--- /dev/null
+++ b/changelogs/unreleased/rc-add_dashboard_path_to_prometheus_metrics.yml
@@ -0,0 +1,5 @@
+---
+title: Add dashboard_path to PrometheusMetric
+merge_request: 38237
+author:
+type: added
diff --git a/changelogs/unreleased/sh-update-gitlab-shell.yml b/changelogs/unreleased/sh-update-gitlab-shell.yml
new file mode 100644
index 00000000000..6d3249bc52a
--- /dev/null
+++ b/changelogs/unreleased/sh-update-gitlab-shell.yml
@@ -0,0 +1,5 @@
+---
+title: Update gitlab-shell to v13.5.0
+merge_request: 38720
+author:
+type: added
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-19-2.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-19-2.yml
new file mode 100644
index 00000000000..ee9a3055aaf
--- /dev/null
+++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-19-2.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.19.2
+merge_request:
+author:
+type: security
diff --git a/config/routes.rb b/config/routes.rb
index fa84b5e50c7..b1ab4ec6bab 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -25,7 +25,8 @@ Rails.application.routes.draw do
controllers applications: 'oauth/applications',
authorized_applications: 'oauth/authorized_applications',
authorizations: 'oauth/authorizations',
- token_info: 'oauth/token_info'
+ token_info: 'oauth/token_info',
+ tokens: 'oauth/tokens'
end
# This prefixless path is required because Jira gets confused if we set it up with a path
diff --git a/db/migrate/20200729175935_add_dashboard_path_to_prometheus_metrics.rb b/db/migrate/20200729175935_add_dashboard_path_to_prometheus_metrics.rb
new file mode 100644
index 00000000000..0562e8d1c14
--- /dev/null
+++ b/db/migrate/20200729175935_add_dashboard_path_to_prometheus_metrics.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class AddDashboardPathToPrometheusMetrics < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ # Text limit is added in 20200730210506_add_text_limit_to_dashboard_path
+ add_column :prometheus_metrics, :dashboard_path, :text # rubocop:disable Migration/AddLimitToTextColumns
+ end
+
+ def down
+ remove_column :prometheus_metrics, :dashboard_path
+ end
+end
diff --git a/db/migrate/20200730210506_add_text_limit_to_dashboard_path.rb b/db/migrate/20200730210506_add_text_limit_to_dashboard_path.rb
new file mode 100644
index 00000000000..a236cc68988
--- /dev/null
+++ b/db/migrate/20200730210506_add_text_limit_to_dashboard_path.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddTextLimitToDashboardPath < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit(:prometheus_metrics, :dashboard_path, 2048)
+ end
+
+ def down
+ remove_text_limit(:prometheus_metrics, :dashboard_path)
+ end
+end
diff --git a/db/schema_migrations/20200729175935 b/db/schema_migrations/20200729175935
new file mode 100644
index 00000000000..65aec146116
--- /dev/null
+++ b/db/schema_migrations/20200729175935
@@ -0,0 +1 @@
+5f841d2032b55f01e944c50070a6bb102883c2e4da7ba155fdcf2e90f3b68707
\ No newline at end of file
diff --git a/db/schema_migrations/20200730210506 b/db/schema_migrations/20200730210506
new file mode 100644
index 00000000000..b140941092d
--- /dev/null
+++ b/db/schema_migrations/20200730210506
@@ -0,0 +1 @@
+85eb0a510cdb4b315aef1665f05ad3b93d5d39f4ddfe11ed5ddde63aa732f874
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index d3fbf7a202f..991112e8564 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -14657,7 +14657,9 @@ CREATE TABLE public.prometheus_metrics (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
common boolean DEFAULT false NOT NULL,
- identifier character varying
+ identifier character varying,
+ dashboard_path text,
+ CONSTRAINT check_0ad9f01463 CHECK ((char_length(dashboard_path) <= 2048))
);
CREATE SEQUENCE public.prometheus_metrics_id_seq
diff --git a/doc/api/graphql/img/sample_issue_boards_v13_2.png b/doc/api/graphql/img/sample_issue_boards_v13_2.png
new file mode 100644
index 00000000000..caa68c82072
Binary files /dev/null and b/doc/api/graphql/img/sample_issue_boards_v13_2.png differ
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index d653c4e0f47..c513dea239a 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -14,7 +14,15 @@ For those new to the GitLab GraphQL API, see
- Get an [introduction to GraphQL from graphql.org](https://graphql.org/).
- GitLab supports a wide range of resources, listed in the [GraphQL API Reference](reference/index.md).
-#### GraphiQL
+### Examples
+
+To work with sample queries that pull data from public projects on GitLab.com,
+see the menu options in the left-hand
+documentation menu, under API > GraphQL at `https://docs.gitlab.com/ee/api/graphql/`.
+
+The [Getting started](getting_started.md) page includes different methods to customize GraphQL queries.
+
+### GraphiQL
Explore the GraphQL API using the interactive [GraphiQL explorer](https://gitlab.com/-/graphql-explorer),
or on your self-managed GitLab instance on
diff --git a/doc/api/graphql/sample_issue_boards.md b/doc/api/graphql/sample_issue_boards.md
new file mode 100644
index 00000000000..4ac9317b01a
--- /dev/null
+++ b/doc/api/graphql/sample_issue_boards.md
@@ -0,0 +1,44 @@
+# Identify issue boards with GraphQL
+
+This page describes how you can use the GraphiQL explorer to identify
+existing issue boards in the `gitlab-docs` documentation repository.
+
+## Set up the GraphiQL explorer
+
+This procedure presents a substantive example that you can copy and paste into your own
+instance of the [GraphiQL explorer](https://gitlab.com/-/graphql-explorer):
+
+1. Copy the following code excerpt:
+
+ ```graphql
+ query {
+ project(fullPath: "gitlab-org/gitlab-docs") {
+ name
+ forksCount
+ statistics {
+ wikiSize
+ }
+ issuesEnabled
+ boards {
+ nodes {
+ id
+ name
+ }
+ }
+ }
+ }
+ ```
+
+1. Open the [GraphiQL Explorer](https://gitlab.com/-/graphql-explorer) page.
+1. Paste the `query` listed above into the left window of your GraphiQL explorer tool.
+1. Click Play to get the result shown here:
+
+
+
+If you want to view one of these boards, take one of the numeric identifiers shown in the output. From the screenshot, the first identifier is `105011`. Navigate to the following URL, which includes the identifier:
+
+```markdown
+https://gitlab.com/gitlab-org/gitlab-docs/-/boards/105011
+```
+
+For more information on each attribute, see the [GraphQL API Resources](reference/index.md).
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index dbe662c3ab2..7ab34b871b0 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -3479,10 +3479,6 @@ job split into three separate jobs.
#### Parallel `matrix` jobs
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15356) in GitLab 13.3.
-> - It's deployed behind a feature flag, disabled by default.
-> - It's enabled on GitLab.com.
-> - It can't be enabled or disabled per-project.
-> - It's recommended for production use.
`matrix:` allows you to configure different variables for jobs that are running in parallel.
There can be from 2 to 50 jobs.
diff --git a/doc/development/documentation/structure.md b/doc/development/documentation/structure.md
index 15a8728bef8..44df003494e 100644
--- a/doc/development/documentation/structure.md
+++ b/doc/development/documentation/structure.md
@@ -104,13 +104,11 @@ Link each one to an appropriate place for more information.
## Instructions
-"Instructions" is usually not the name of the heading.
-
-This is the part of the document where you can include one or more sets of instructions,
-each to accomplish a specific task.
+This is the part of the document where you can include one or more sets of instructions.
+Each topic should help users accomplish a specific task.
Headers should describe the task the reader will achieve by following the instructions within,
-typically starting with a verb.
+typically starting with a verb. For example, `Create a package` or `Configure a pipeline`.
Larger instruction sets may have subsections covering specific phases of the process.
Where appropriate, provide examples of code or configuration files to better clarify
@@ -127,6 +125,32 @@ intended usage.
single heading like `## Configure X` for instructions when the feature
is simple and the document is short.
+Example topic:
+
+## Create a teddy bear
+
+Start by writing a sentence or two about _why_ someone would want to perform this task.
+It's not always possible, but is a good practice. For example:
+
+Create a teddy bear when you need something to hug.
+
+Follow this information with the task steps.
+
+To create a teddy bear:
+
+1. Go to **Settings > CI/CD**.
+1. Expand **This** and click **This**.
+1. Do another step.
+
+After the numbered list, add a sentence with the expected result, if it
+is not obvious, and any next steps. For example:
+
+The teddy bear is now in the kitchen, in the cupboard above the sink.
+
+You can retrieve the teddy bear and put it on the couch with the other animals.
+
+Screenshots are not necessary. They are difficult to keep up-to-date and can clutter the page.
+