summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/issue_templates/Security Release.md20
-rw-r--r--.gitlab/issue_templates/Security developer workflow.md2
-rw-r--r--CHANGELOG.md13
-rw-r--r--app/assets/javascripts/notes/stores/utils.js2
-rw-r--r--app/assets/javascripts/operation_settings/components/external_dashboard.vue2
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue2
-rw-r--r--app/assets/javascripts/right_sidebar.js10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue11
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss16
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/finders/branches_finder.rb2
-rw-r--r--app/finders/container_repositories_finder.rb34
-rw-r--r--app/models/group.rb2
-rw-r--r--app/policies/group_policy.rb1
-rw-r--r--app/serializers/analytics_issue_entity.rb2
-rw-r--r--app/views/admin/users/_access_levels.html.haml4
-rw-r--r--changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml6
-rw-r--r--changelogs/unreleased/64675-Dashboard-URL-legend-border.yml5
-rw-r--r--changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml5
-rw-r--r--changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml5
-rw-r--r--changelogs/unreleased/fix-i18n-updated-projects.yml5
-rw-r--r--changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml5
-rw-r--r--changelogs/unreleased/leipert-improve-ansi2html.yml5
-rw-r--r--changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml5
-rw-r--r--changelogs/unreleased/patch-72.yml5
-rw-r--r--changelogs/unreleased/sh-disable-redis-peek.yml5
-rw-r--r--doc/administration/index.md2
-rw-r--r--doc/administration/plugins.md32
-rw-r--r--doc/administration/troubleshooting/diagnostics_tools.md27
-rw-r--r--doc/api/container_registry.md77
-rw-r--r--doc/user/project/pipelines/settings.md7
-rw-r--r--doc/user/project/quick_actions.md13
-rw-r--r--lib/api/api.rb3
-rw-r--r--lib/api/entities/container_registry.rb10
-rw-r--r--lib/api/group_container_repositories.rb39
-rw-r--r--lib/api/project_container_repositories.rb (renamed from lib/api/container_registry.rb)21
-rw-r--r--lib/gitlab/background_migration/migrate_legacy_artifacts.rb18
-rw-r--r--lib/gitlab/cycle_analytics/base_query.rb13
-rw-r--r--lib/gitlab/cycle_analytics/code_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/issue_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/issue_helper.rb13
-rw-r--r--lib/gitlab/cycle_analytics/plan_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/plan_helper.rb6
-rw-r--r--lib/gitlab/cycle_analytics/production_event_fetcher.rb1
-rw-r--r--lib/gitlab/cycle_analytics/review_event_fetcher.rb4
-rw-r--r--lib/peek/views/redis_detailed.rb5
-rw-r--r--package.json2
-rw-r--r--spec/factories/clusters/applications/helm.rb14
-rw-r--r--spec/finders/container_repositories_finder_spec.rb44
-rw-r--r--spec/fixtures/api/schemas/registry/repository.json6
-rw-r--r--spec/fixtures/clusters/sample_key.key9
-rw-r--r--spec/models/group_spec.rb1
-rw-r--r--spec/requests/api/group_container_repositories_spec.rb57
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb (renamed from spec/requests/api/container_registry_spec.rb)75
-rw-r--r--spec/serializers/analytics_issue_entity_spec.rb6
-rw-r--r--spec/serializers/analytics_issue_serializer_spec.rb6
-rw-r--r--spec/serializers/analytics_merge_request_serializer_spec.rb6
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb2
-rw-r--r--spec/support/shared_examples/container_repositories_shared_examples.rb58
-rw-r--r--yarn.lock8
60 files changed, 606 insertions, 167 deletions
diff --git a/.gitlab/issue_templates/Security Release.md b/.gitlab/issue_templates/Security Release.md
index ae469d3b125..3e60274623e 100644
--- a/.gitlab/issue_templates/Security Release.md
+++ b/.gitlab/issue_templates/Security Release.md
@@ -1,7 +1,7 @@
<!--
# Read me first!
-Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
+Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
-->
## Releases tasks
@@ -12,9 +12,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
## Version issues:
-* 11.4.X: {release task link}
-* 11.3.X: {release task link}
-* 11.2.X: {release task link}
+* 12.2.X: {release task link}
+* 12.1.X: {release task link}
+* 12.0.X: {release task link}
## Security Issues:
@@ -34,9 +34,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
| Version | MR |
|---------|----|
-| 11.4 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
-| 11.3 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
-| 11.2 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
+| 12.2 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
+| 12.1 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
+| 12.0 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
@@ -48,9 +48,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
| Version | MR |
|---------|----|
-| 11.4| {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
-| 11.3 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
-| 11.2 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
+| 12.2 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
+| 12.1 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
+| 12.0 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md
index 7857afb66c2..3e634de4f0c 100644
--- a/.gitlab/issue_templates/Security developer workflow.md
+++ b/.gitlab/issue_templates/Security developer workflow.md
@@ -17,7 +17,7 @@ Set the title to: `Description of the original issue`
#### Backports
-- [ ] Once the MR is ready to be merged, create MRs targeting the last 3 releases, plus the current RC if between the 7th and 22nd of the month.
+- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches
- [ ] At this point, it might be easy to squash the commits from the MR into one
- You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the "Security Release" merge request template.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15b55f01c32..0752708d5e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,19 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 12.1.4
+
+### Fixed (3 changes, 1 of them is from the community)
+
+- Properly translate term in projects list. !30958
+- Add exclusive lease to mergeability check process. !31082
+- Fix Docker in Docker (DIND) listen port behavior change by adding DOCKER_TLS_CERTDIR in CI job templates. !31201 (Cameron Boulton)
+
+### Performance (1 change)
+
+- Improve job log rendering performance. !31262
+
+
## 12.1.3
### Fixed (11 changes)
diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js
index ed4cef4a917..97dcd54fe88 100644
--- a/app/assets/javascripts/notes/stores/utils.js
+++ b/app/assets/javascripts/notes/stores/utils.js
@@ -21,7 +21,7 @@ export const getQuickActionText = note => {
text = __('Applying multiple commands');
} else {
const commandDescription = executedCommands[0].description.toLowerCase();
- text = sprintf(__('Applying command to %{commandDescription}', { commandDescription }));
+ text = sprintf(__('Applying command to %{commandDescription}'), { commandDescription });
}
}
diff --git a/app/assets/javascripts/operation_settings/components/external_dashboard.vue b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
index ed518611d0b..3c5de189d51 100644
--- a/app/assets/javascripts/operation_settings/components/external_dashboard.vue
+++ b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
@@ -50,9 +50,11 @@ export default {
<form>
<gl-form-group
:label="s__('ExternalMetrics|Full dashboard URL')"
+ label-for="full-dashboard-url"
:description="s__('ExternalMetrics|Enter the URL of the dashboard you want to link to')"
>
<gl-form-input
+ id="full-dashboard-url"
v-model="userDashboardUrl"
placeholder="https://my-org.gitlab.io/my-dashboards"
@keydown.enter.native.prevent="updateExternalDashboardUrl"
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index 9bc3e6388e3..24612c8681a 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -166,7 +166,7 @@ export default {
<section class="media-section">
<div class="media">
<status-icon :status="statusIconName" :size="24" />
- <div class="media-body d-flex flex-align-self-center prepend-left-default">
+ <div class="media-body d-flex flex-align-self-center">
<span class="js-code-text code-text">
{{ headerText }}
<slot :name="slotName"></slot>
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 930c0d5e958..40a2158de78 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -101,10 +101,12 @@ Sidebar.prototype.toggleTodo = function(e) {
this.todoUpdateDone(data);
})
.catch(() =>
- flash(sprintf(__('There was an error %{message} todo.')), {
- message:
- ajaxType === 'post' ? s__('RightSidebar|adding a') : s__('RightSidebar|deleting the'),
- }),
+ flash(
+ sprintf(__('There was an error %{message} todo.'), {
+ message:
+ ajaxType === 'post' ? s__('RightSidebar|adding a') : s__('RightSidebar|deleting the'),
+ }),
+ ),
);
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
index 8dbd9e52cfe..13e4b061fda 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -32,10 +32,13 @@ export default {
};
</script>
<template>
- <div class="d-flex widget-status-icon">
- <div v-if="isLoading" class="mr-widget-icon"><gl-loading-icon size="sm" /></div>
-
- <ci-icon v-else :status="statusObj" :size="24" />
+ <div class="d-flex align-self-start">
+ <div class="square s24 h-auto d-flex-center append-right-default">
+ <div v-if="isLoading" class="mr-widget-icon">
+ <gl-loading-icon size="sm" />
+ </div>
+ <ci-icon v-else :status="statusObj" :size="24" />
+ </div>
<button
v-if="showDisabledButton"
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 2780afa11fa..cb7913ee54e 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -88,7 +88,7 @@
}
.mr-widget-info {
- padding-left: $gl-padding-50 - $gl-padding-32;
+ padding-left: $gl-padding;
padding-right: $gl-padding;
}
@@ -262,23 +262,11 @@
}
}
- .widget-status-icon {
- align-self: flex-start;
-
- button {
- margin-left: $gl-padding;
- }
- }
-
.mr-widget-body {
line-height: 28px;
@include clearfix;
- button {
- margin-left: $gl-padding;
- }
-
.approve-btn {
margin-right: 5px;
}
@@ -527,7 +515,7 @@
}
.mr-links {
- padding-left: $status-icon-size + $gl-btn-padding;
+ padding-left: $gl-padding-8 + $status-icon-size + $gl-btn-padding;
&:last-child {
padding-bottom: $gl-padding;
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 141a7dfb923..e7bdb4b2042 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -49,7 +49,7 @@ class Projects::BranchesController < Projects::ApplicationController
branches = BranchesFinder.new(repository, params.permit(names: [])).execute
Gitlab::GitalyClient.allow_n_plus_1_calls do
- render json: branches.to_h { |branch| [branch.name, service.call(branch)] }
+ render json: branches.map { |branch| [branch.name, service.call(branch)] }.to_h
end
end
end
diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb
index b462c8053fa..291a24c1405 100644
--- a/app/finders/branches_finder.rb
+++ b/app/finders/branches_finder.rb
@@ -69,7 +69,7 @@ class BranchesFinder
return branches unless names
branch_names = names.to_set
- branches.filter do |branch|
+ branches.select do |branch|
branch_names.include?(branch.name)
end
end
diff --git a/app/finders/container_repositories_finder.rb b/app/finders/container_repositories_finder.rb
new file mode 100644
index 00000000000..eb91d7f825b
--- /dev/null
+++ b/app/finders/container_repositories_finder.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class ContainerRepositoriesFinder
+ # id: group or project id
+ # container_type: :group or :project
+ def initialize(id:, container_type:)
+ @id = id
+ @type = container_type.to_sym
+ end
+
+ def execute
+ if project_type?
+ project.container_repositories
+ else
+ group.container_repositories
+ end
+ end
+
+ private
+
+ attr_reader :id, :type
+
+ def project_type?
+ type == :project
+ end
+
+ def project
+ Project.find(id)
+ end
+
+ def group
+ Group.find(id)
+ end
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index 74eb556b1b5..6c868b1d1f0 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -44,6 +44,8 @@ class Group < Namespace
has_many :cluster_groups, class_name: 'Clusters::Group'
has_many :clusters, through: :cluster_groups, class_name: 'Clusters::Cluster'
+ has_many :container_repositories, through: :projects
+
has_many :todos
accepts_nested_attributes_for :variables, allow_destroy: true
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 84b1873c05d..52c944491bf 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -68,6 +68,7 @@ class GroupPolicy < BasePolicy
rule { developer }.enable :admin_milestone
rule { reporter }.policy do
+ enable :read_container_image
enable :admin_label
enable :admin_list
enable :admin_issue
diff --git a/app/serializers/analytics_issue_entity.rb b/app/serializers/analytics_issue_entity.rb
index 29d4a6ae1d0..307ce14a921 100644
--- a/app/serializers/analytics_issue_entity.rb
+++ b/app/serializers/analytics_issue_entity.rb
@@ -26,6 +26,6 @@ class AnalyticsIssueEntity < Grape::Entity
private
def url_to(route, object)
- public_send("#{route}_url", object[:path], object[:name], object[:iid].to_s) # rubocop:disable GitlabSecurity/PublicSend
+ public_send("#{route}_url", object[:namespace_path], object[:project_path], object[:iid].to_s) # rubocop:disable GitlabSecurity/PublicSend
end
end
diff --git a/app/views/admin/users/_access_levels.html.haml b/app/views/admin/users/_access_levels.html.haml
index 77729636f9d..bb1e22cc610 100644
--- a/app/views/admin/users/_access_levels.html.haml
+++ b/app/views/admin/users/_access_levels.html.haml
@@ -19,7 +19,7 @@
- editing_current_user = (current_user == @user)
= f.radio_button :access_level, :regular, disabled: editing_current_user
- = label_tag :regular, class: 'font-weight-bold' do
+ = f.label :access_level_regular, class: 'font-weight-bold' do
Regular
%p.light
Regular users have access to their groups and projects
@@ -27,7 +27,7 @@
= render_if_exists 'admin/users/auditor_access_level_radio', f: f, disabled: editing_current_user
= f.radio_button :access_level, :admin, disabled: editing_current_user
- = label_tag :admin, class: 'font-weight-bold' do
+ = f.label :access_level_admin, class: 'font-weight-bold' do
Admin
%p.light
Administrators have access to all groups, projects and users and can manage all features in this installation
diff --git a/changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml b/changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml
new file mode 100644
index 00000000000..adbd7971a14
--- /dev/null
+++ b/changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml
@@ -0,0 +1,6 @@
+---
+title: Add API endpoints to return container repositories and tags from the group
+ level
+merge_request: 30817
+author:
+type: added
diff --git a/changelogs/unreleased/64675-Dashboard-URL-legend-border.yml b/changelogs/unreleased/64675-Dashboard-URL-legend-border.yml
new file mode 100644
index 00000000000..f35261fcd6c
--- /dev/null
+++ b/changelogs/unreleased/64675-Dashboard-URL-legend-border.yml
@@ -0,0 +1,5 @@
+---
+title: Removed extrenal dashboard legend border
+merge_request: 31407
+author:
+type: fixed
diff --git a/changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml b/changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml
new file mode 100644
index 00000000000..2a45eec78ef
--- /dev/null
+++ b/changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml
@@ -0,0 +1,5 @@
+---
+title: Add space to "merged by" widget
+merge_request: 30972
+author:
+type: fixed
diff --git a/changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml b/changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml
new file mode 100644
index 00000000000..4f119d46a1f
--- /dev/null
+++ b/changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml
@@ -0,0 +1,5 @@
+---
+title: Fix admin area user access level radio button labels
+merge_request: 31154
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-i18n-updated-projects.yml b/changelogs/unreleased/fix-i18n-updated-projects.yml
deleted file mode 100644
index 408ee438480..00000000000
--- a/changelogs/unreleased/fix-i18n-updated-projects.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Properly translate term in projects list
-merge_request: 30958
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml b/changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml
new file mode 100644
index 00000000000..7d171c2cf5b
--- /dev/null
+++ b/changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken issue links and possible 500 error on cycle analytics page when project name and path are different
+merge_request: 31471
+author:
+type: fixed
diff --git a/changelogs/unreleased/leipert-improve-ansi2html.yml b/changelogs/unreleased/leipert-improve-ansi2html.yml
deleted file mode 100644
index dd3582b3434..00000000000
--- a/changelogs/unreleased/leipert-improve-ansi2html.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve job log rendering performance
-merge_request: 31262
-author:
-type: performance
diff --git a/changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml b/changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml
deleted file mode 100644
index 17ff1b012cf..00000000000
--- a/changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add exclusive lease to mergeability check process
-merge_request: 31082
-author:
-type: fixed
diff --git a/changelogs/unreleased/patch-72.yml b/changelogs/unreleased/patch-72.yml
deleted file mode 100644
index ff2bac2fc29..00000000000
--- a/changelogs/unreleased/patch-72.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Docker in Docker (DIND) listen port behavior change by adding DOCKER_TLS_CERTDIR in CI job templates.
-merge_request: 31201
-author: Cameron Boulton
-type: fixed
diff --git a/changelogs/unreleased/sh-disable-redis-peek.yml b/changelogs/unreleased/sh-disable-redis-peek.yml
new file mode 100644
index 00000000000..de86c0031c7
--- /dev/null
+++ b/changelogs/unreleased/sh-disable-redis-peek.yml
@@ -0,0 +1,5 @@
+---
+title: Only track Redis calls if Peek is enabled
+merge_request: 31438
+author:
+type: performance
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 00c8863f200..febee3e5af8 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -185,3 +185,5 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Debugging tips](troubleshooting/debug.md): Tips to debug problems when things go wrong
- [Log system](logs.md): Where to look for logs.
- [Sidekiq Troubleshooting](troubleshooting/sidekiq.md): Debug when Sidekiq appears hung and is not processing jobs.
+- Useful [diagnostics tools](troubleshooting/diagnostics_tools.md) that are sometimes used by the GitLab
+ Support team.
diff --git a/doc/administration/plugins.md b/doc/administration/plugins.md
index 4302667caf5..4cf3c607dae 100644
--- a/doc/administration/plugins.md
+++ b/doc/administration/plugins.md
@@ -52,7 +52,37 @@ as appropriate. The plugins file list is updated for each event, there is no
need to restart GitLab to apply a new plugin.
If a plugin executes with non-zero exit code or GitLab fails to execute it, a
-message will be logged to `plugin.log`.
+message will be logged to:
+
+- `gitlab-rails/plugin.log` in an Omnibus installation.
+- `log/plugin.log` in a source installation.
+
+## Creating plugins
+
+Below is an example that will only response on the event `project_create` and
+will inform the admins from the GitLab instance that a new project has been created.
+
+```ruby
+# By using the embedded ruby version we eliminate the possibility that our chosen language
+# would be unavailable from
+#!/opt/gitlab/embedded/bin/ruby
+require 'json'
+require 'mail'
+
+# The incoming variables are in JSON format so we need to parse it first.
+ARGS = JSON.parse(STDIN.read)
+
+# We only want to trigger this plugin on the event project_create
+return unless ARGS['event_name'] == 'project_create'
+
+# We will inform our admins of our gitlab instance that a new project is created
+Mail.deliver do
+ from 'info@gitlab_instance.com'
+ to 'admin@gitlab_instance.com'
+ subject "new project " + ARGS['name']
+ body ARGS['owner_name'] + 'created project ' + ARGS['name']
+end
+```
## Validation
diff --git a/doc/administration/troubleshooting/diagnostics_tools.md b/doc/administration/troubleshooting/diagnostics_tools.md
new file mode 100644
index 00000000000..ab3b25f0e97
--- /dev/null
+++ b/doc/administration/troubleshooting/diagnostics_tools.md
@@ -0,0 +1,27 @@
+---
+type: reference
+---
+
+# Diagnostics tools
+
+These are some of the diagnostics tools the GitLab Support team uses during troubleshooting.
+They are listed here for transparency, and they may be useful for users with experience
+with troubleshooting GitLab. If you are currently having an issue with GitLab, you
+may want to check your [support options](https://about.gitlab.com/support/) first,
+before attempting to use these tools.
+
+## gitlabsos
+
+The [gitlabsos](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/) utility
+provides a unified method of gathering info and logs from GitLab and the system it's
+running on.
+
+## strace-parser
+
+[strace-parser](https://gitlab.com/wchandler/strace-parser) is a small tool to analyze
+and summarize raw strace data.
+
+## Pritaly
+
+[Pritaly](https://gitlab.com/wchandler/pritaly) takes Gitaly logs and colorizes output
+or converts the logs to JSON.
diff --git a/doc/api/container_registry.md b/doc/api/container_registry.md
index 174b93a4f7a..bf544f64178 100644
--- a/doc/api/container_registry.md
+++ b/doc/api/container_registry.md
@@ -6,6 +6,8 @@ This is the API docs of the [GitLab Container Registry](../user/project/containe
## List registry repositories
+### Within a project
+
Get a list of registry repositories in a project.
```
@@ -14,7 +16,8 @@ GET /projects/:id/registry/repositories
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
+| `tags` | boolean | no | If the param is included as true, each repository will include an array of `"tags"` in the response. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories"
@@ -28,6 +31,7 @@ Example response:
"id": 1,
"name": "",
"path": "group/project",
+ "project_id": 9,
"location": "gitlab.example.com:5000/group/project",
"created_at": "2019-01-10T13:38:57.391Z"
},
@@ -35,12 +39,77 @@ Example response:
"id": 2,
"name": "releases",
"path": "group/project/releases",
+ "project_id": 9,
"location": "gitlab.example.com:5000/group/project/releases",
"created_at": "2019-01-10T13:39:08.229Z"
}
]
```
+### Within a group
+
+Get a list of registry repositories in a group.
+
+```
+GET /groups/:id/registry/repositories
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. |
+| `tags` | boolean | no | If the param is included as true, each repository will include an array of `"tags"` in the response. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/2/registry/repositories?tags=1"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "name": "",
+ "path": "group/project",
+ "project_id": 9,
+ "location": "gitlab.example.com:5000/group/project",
+ "created_at": "2019-01-10T13:38:57.391Z",
+ "tags": [
+ {
+ "name": "0.0.1",
+ "path": "group/project:0.0.1",
+ "location": "gitlab.example.com:5000/group/project:0.0.1"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "name": "",
+ "path": "group/other_project",
+ "project_id": 11,
+ "location": "gitlab.example.com:5000/group/other_project",
+ "created_at": "2019-01-10T13:39:08.229Z",
+ "tags": [
+ {
+ "name": "0.0.1",
+ "path": "group/other_project:0.0.1",
+ "location": "gitlab.example.com:5000/group/other_project:0.0.1"
+ },
+ {
+ "name": "0.0.2",
+ "path": "group/other_project:0.0.2",
+ "location": "gitlab.example.com:5000/group/other_project:0.0.2"
+ },
+ {
+ "name": "latest",
+ "path": "group/other_project:latest",
+ "location": "gitlab.example.com:5000/group/other_project:latest"
+ }
+ ]
+ }
+]
+```
+
## Delete registry repository
Delete a repository in registry.
@@ -62,6 +131,8 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
## List repository tags
+### Within a project
+
Get a list of tags for given registry repository.
```
@@ -70,7 +141,7 @@ GET /projects/:id/registry/repositories/:repository_id/tags
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `repository_id` | integer | yes | The ID of registry repository. |
```bash
@@ -104,7 +175,7 @@ GET /projects/:id/registry/repositories/:repository_id/tags/:tag_name
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `repository_id` | integer | yes | The ID of registry repository. |
| `tag_name` | string | yes | The name of tag. |
diff --git a/doc/user/project/pipelines/settings.md b/doc/user/project/pipelines/settings.md
index 45f27b3c811..456209c2180 100644
--- a/doc/user/project/pipelines/settings.md
+++ b/doc/user/project/pipelines/settings.md
@@ -76,6 +76,13 @@ Here are some valid examples:
- `my/path/.gitlab-ci.yml`
- `my/path/.my-custom-file.yml`
+The path can be customized at a project level. To customize the path:
+
+1. Go to the project's **Settings > CI / CD**.
+1. Expand the **General pipelines** section.
+1. Provide a value in the **Custom CI config path** field.
+1. Click **Save changes**.
+
## Test coverage parsing
If you use test coverage in your code, GitLab can capture its output in the
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index b8e0ef8d12f..437899dce1e 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -70,6 +70,19 @@ Many quick actions require a parameter, for example: username, milestone, and
label. [Autocomplete characters](autocomplete_characters.md) can make it easier
to enter a parameter, compared to selecting items from a list.
+## Quick actions parameters
+
+The easiest way to set parameters for quick actions is to use autocomplete. If
+you manually enter a parameter, it must be enclosed in double quotation marks
+(`"`), unless it contains only:
+
+1. ASCII letters.
+2. Numerals.
+3. Underscore, hyphen, question mark, dot, and ampersand.
+
+Parameters are also case-sensitive. Autocomplete handles this, and the insertion
+of quotation marks, automatically.
+
## Quick actions for commit messages
The following quick actions are applicable for commit messages:
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 223ae13bd2d..e500a93b31e 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -104,7 +104,6 @@ module API
mount ::API::BroadcastMessages
mount ::API::Commits
mount ::API::CommitStatuses
- mount ::API::ContainerRegistry
mount ::API::DeployKeys
mount ::API::Deployments
mount ::API::Environments
@@ -116,6 +115,7 @@ module API
mount ::API::GroupLabels
mount ::API::GroupMilestones
mount ::API::Groups
+ mount ::API::GroupContainerRepositories
mount ::API::GroupVariables
mount ::API::ImportGithub
mount ::API::Internal
@@ -138,6 +138,7 @@ module API
mount ::API::Pipelines
mount ::API::PipelineSchedules
mount ::API::ProjectClusters
+ mount ::API::ProjectContainerRepositories
mount ::API::ProjectEvents
mount ::API::ProjectExport
mount ::API::ProjectImport
diff --git a/lib/api/entities/container_registry.rb b/lib/api/entities/container_registry.rb
index 00833ca7480..6250f35c7cb 100644
--- a/lib/api/entities/container_registry.rb
+++ b/lib/api/entities/container_registry.rb
@@ -3,18 +3,20 @@
module API
module Entities
module ContainerRegistry
- class Repository < Grape::Entity
- expose :id
+ class Tag < Grape::Entity
expose :name
expose :path
expose :location
- expose :created_at
end
- class Tag < Grape::Entity
+ class Repository < Grape::Entity
+ expose :id
expose :name
expose :path
+ expose :project_id
expose :location
+ expose :created_at
+ expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
end
class TagDetails < Tag
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
new file mode 100644
index 00000000000..fd24662cc9a
--- /dev/null
+++ b/lib/api/group_container_repositories.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module API
+ class GroupContainerRepositories < Grape::API
+ include PaginationParams
+
+ before { authorize_read_group_container_images! }
+
+ REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
+ tag_name: API::NO_SLASH_URL_PART_REGEX)
+
+ params do
+ requires :id, type: String, desc: "Group's ID or path"
+ end
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ desc 'Get a list of all repositories within a group' do
+ detail 'This feature was introduced in GitLab 12.2.'
+ success Entities::ContainerRegistry::Repository
+ end
+ params do
+ use :pagination
+ optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
+ end
+ get ':id/registry/repositories' do
+ repositories = ContainerRepositoriesFinder.new(
+ id: user_group.id, container_type: :group
+ ).execute
+
+ present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags]
+ end
+ end
+
+ helpers do
+ def authorize_read_group_container_images!
+ authorize! :read_container_image, user_group
+ end
+ end
+ end
+end
diff --git a/lib/api/container_registry.rb b/lib/api/project_container_repositories.rb
index 7dad20a822a..6d53abcc500 100644
--- a/lib/api/container_registry.rb
+++ b/lib/api/project_container_repositories.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
module API
- class ContainerRegistry < Grape::API
+ class ProjectContainerRepositories < Grape::API
include PaginationParams
- REGISTRY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
+ REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
tag_name: API::NO_SLASH_URL_PART_REGEX)
before { error!('404 Not Found', 404) unless Feature.enabled?(:container_registry_api, user_project, default_enabled: true) }
@@ -20,11 +20,14 @@ module API
end
params do
use :pagination
+ optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
end
get ':id/registry/repositories' do
- repositories = user_project.container_repositories.ordered
+ repositories = ContainerRepositoriesFinder.new(
+ id: user_project.id, container_type: :project
+ ).execute
- present paginate(repositories), with: Entities::ContainerRegistry::Repository
+ present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags]
end
desc 'Delete repository' do
@@ -33,7 +36,7 @@ module API
params do
requires :repository_id, type: Integer, desc: 'The ID of the repository'
end
- delete ':id/registry/repositories/:repository_id', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ delete ':id/registry/repositories/:repository_id', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image!
DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id)
@@ -49,7 +52,7 @@ module API
requires :repository_id, type: Integer, desc: 'The ID of the repository'
use :pagination
end
- get ':id/registry/repositories/:repository_id/tags', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ get ':id/registry/repositories/:repository_id/tags', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_read_container_image!
tags = Kaminari.paginate_array(repository.tags)
@@ -65,7 +68,7 @@ module API
optional :keep_n, type: Integer, desc: 'Keep n of latest tags with matching name'
optional :older_than, type: String, desc: 'Delete older than: 1h, 1d, 1month'
end
- delete ':id/registry/repositories/:repository_id/tags', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ delete ':id/registry/repositories/:repository_id/tags', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image!
message = 'This request has already been made. You can run this at most once an hour for a given container repository'
@@ -85,7 +88,7 @@ module API
requires :repository_id, type: Integer, desc: 'The ID of the repository'
requires :tag_name, type: String, desc: 'The name of the tag'
end
- get ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ get ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_read_container_image!
validate_tag!
@@ -99,7 +102,7 @@ module API
requires :repository_id, type: Integer, desc: 'The ID of the repository'
requires :tag_name, type: String, desc: 'The name of the tag'
end
- delete ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ delete ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_destroy_container_image!
validate_tag!
diff --git a/lib/gitlab/background_migration/migrate_legacy_artifacts.rb b/lib/gitlab/background_migration/migrate_legacy_artifacts.rb
index 5cd638083b0..4377ec2987c 100644
--- a/lib/gitlab/background_migration/migrate_legacy_artifacts.rb
+++ b/lib/gitlab/background_migration/migrate_legacy_artifacts.rb
@@ -39,10 +39,10 @@ module Gitlab
SELECT
project_id,
id,
- artifacts_expire_at,
+ artifacts_expire_at #{add_missing_db_timezone},
#{LEGACY_PATH_FILE_LOCATION},
- created_at,
- created_at,
+ created_at #{add_missing_db_timezone},
+ created_at #{add_missing_db_timezone},
artifacts_file,
artifacts_size,
COALESCE(artifacts_file_store, #{FILE_LOCAL_STORE}),
@@ -81,10 +81,10 @@ module Gitlab
SELECT
project_id,
id,
- artifacts_expire_at,
+ artifacts_expire_at #{add_missing_db_timezone},
#{LEGACY_PATH_FILE_LOCATION},
- created_at,
- created_at,
+ created_at #{add_missing_db_timezone},
+ created_at #{add_missing_db_timezone},
artifacts_metadata,
NULL,
COALESCE(artifacts_metadata_store, #{FILE_LOCAL_STORE}),
@@ -121,6 +121,12 @@ module Gitlab
AND artifacts_file <> ''
SQL
end
+
+ def add_missing_db_timezone
+ return '' unless Gitlab::Database.postgresql?
+
+ 'at time zone \'UTC\''
+ end
end
end
end
diff --git a/lib/gitlab/cycle_analytics/base_query.rb b/lib/gitlab/cycle_analytics/base_query.rb
index 9c98c0bfbf2..459bb5177b5 100644
--- a/lib/gitlab/cycle_analytics/base_query.rb
+++ b/lib/gitlab/cycle_analytics/base_query.rb
@@ -19,9 +19,10 @@ module Gitlab
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
- .where(issue_table[:project_id].in(project_ids))
- .where(routes_table[:source_type].eq('Namespace'))
- .where(issue_table[:created_at].gteq(options[:from]))
+ .project(projects_table[:path].as("project_path"))
+ .project(routes_table[:path].as("namespace_path"))
+
+ query = limit_query(query, project_ids)
# Load merge_requests
@@ -30,6 +31,12 @@ module Gitlab
query
end
+ def limit_query(query, project_ids)
+ query.where(issue_table[:project_id].in(project_ids))
+ .where(routes_table[:source_type].eq('Namespace'))
+ .where(issue_table[:created_at].gteq(options[:from]))
+ end
+
def load_merge_requests(query)
query.join(mr_table, Arel::Nodes::OuterJoin)
.on(mr_table[:id].eq(mr_closing_issues_table[:merge_request_id]))
diff --git a/lib/gitlab/cycle_analytics/code_event_fetcher.rb b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
index 1e4e9b9e02c..fcc282bf7a6 100644
--- a/lib/gitlab/cycle_analytics/code_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
@@ -11,9 +11,7 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
- mr_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ mr_table[:author_id]]
@order = mr_table[:created_at]
super(*args)
diff --git a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
index 2d03e425a6a..6914cf24c19 100644
--- a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
@@ -10,9 +10,7 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ issue_table[:author_id]]
super(*args)
end
diff --git a/lib/gitlab/cycle_analytics/issue_helper.rb b/lib/gitlab/cycle_analytics/issue_helper.rb
index 0fc4f1dd41a..295eca5edca 100644
--- a/lib/gitlab/cycle_analytics/issue_helper.rb
+++ b/lib/gitlab/cycle_analytics/issue_helper.rb
@@ -8,12 +8,19 @@ module Gitlab
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
- .where(issue_table[:project_id].in(project_ids))
+ .project(projects_table[:path].as("project_path"))
+ .project(routes_table[:path].as("namespace_path"))
+
+ query = limit_query(query, project_ids)
+
+ query
+ end
+
+ def limit_query(query, project_ids)
+ query.where(issue_table[:project_id].in(project_ids))
.where(routes_table[:source_type].eq('Namespace'))
.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
-
- query
end
end
end
diff --git a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
index 77cc358daa9..bad02e00a13 100644
--- a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
@@ -10,9 +10,7 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ issue_table[:author_id]]
super(*args)
end
diff --git a/lib/gitlab/cycle_analytics/plan_helper.rb b/lib/gitlab/cycle_analytics/plan_helper.rb
index c3f742503a9..a63ae58ad21 100644
--- a/lib/gitlab/cycle_analytics/plan_helper.rb
+++ b/lib/gitlab/cycle_analytics/plan_helper.rb
@@ -8,14 +8,16 @@ module Gitlab
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
+ .project(projects_table[:path].as("project_path"))
+ .project(routes_table[:path].as("namespace_path"))
.where(issue_table[:project_id].in(project_ids))
.where(routes_table[:source_type].eq('Namespace'))
- query = add_conditions_to_query(query)
+ query = limit_query(query)
query
end
- def add_conditions_to_query(query)
+ def limit_query(query)
query.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
.where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
diff --git a/lib/gitlab/cycle_analytics/production_event_fetcher.rb b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
index 404b2460814..8843ab2bcb9 100644
--- a/lib/gitlab/cycle_analytics/production_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
@@ -11,7 +11,6 @@ module Gitlab
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id],
- projects_table[:name],
routes_table[:path]]
super(*args)
diff --git a/lib/gitlab/cycle_analytics/review_event_fetcher.rb b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
index 6acd12517fa..4b5d79097b7 100644
--- a/lib/gitlab/cycle_analytics/review_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
@@ -11,9 +11,7 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
- mr_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ mr_table[:author_id]]
super(*args)
end
diff --git a/lib/peek/views/redis_detailed.rb b/lib/peek/views/redis_detailed.rb
index b95307deddb..f36f581d5e9 100644
--- a/lib/peek/views/redis_detailed.rb
+++ b/lib/peek/views/redis_detailed.rb
@@ -16,6 +16,7 @@ module Gitlab
private
def add_call_details(duration, args)
+ return unless peek_enabled?
# redis-rb passes an array (e.g. [:get, key])
return unless args.length == 1
@@ -26,6 +27,10 @@ module Gitlab
}
end
+ def peek_enabled?
+ Gitlab::SafeRequestStore.store[:peek_enabled]
+ end
+
def detail_store
::Gitlab::SafeRequestStore['redis_call_details'] ||= []
end
diff --git a/package.json b/package.json
index bf6000dc53d..4ff99f29e24 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0",
"@gitlab/svgs": "^1.67.0",
- "@gitlab/ui": "5.12.1",
+ "@gitlab/ui": "5.14.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 24c22ef3928..89f7bc15217 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -4,6 +4,20 @@ FactoryBot.define do
factory :clusters_applications_helm, class: Clusters::Applications::Helm do
cluster factory: %i(cluster provided_by_gcp)
+ before(:create) do
+ allow(Gitlab::Kubernetes::Helm::Certificate).to receive(:generate_root)
+ .and_return(
+ double(
+ key_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_key.key')),
+ cert_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem'))
+ )
+ )
+ end
+
+ after(:create) do
+ allow(Gitlab::Kubernetes::Helm::Certificate).to receive(:generate_root).and_call_original
+ end
+
trait :not_installable do
status(-2)
end
diff --git a/spec/finders/container_repositories_finder_spec.rb b/spec/finders/container_repositories_finder_spec.rb
new file mode 100644
index 00000000000..deec62d6598
--- /dev/null
+++ b/spec/finders/container_repositories_finder_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ContainerRepositoriesFinder do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+ let(:project_repository) { create(:container_repository, project: project) }
+
+ describe '#execute' do
+ let(:id) { nil }
+
+ subject { described_class.new(id: id, container_type: container_type).execute }
+
+ context 'when container_type is group' do
+ let(:other_project) { create(:project, group: group) }
+
+ let(:other_repository) do
+ create(:container_repository, name: 'test_repository2', project: other_project)
+ end
+
+ let(:container_type) { :group }
+ let(:id) { group.id }
+
+ it { is_expected.to match_array([project_repository, other_repository]) }
+ end
+
+ context 'when container_type is project' do
+ let(:container_type) { :project }
+ let(:id) { project.id }
+
+ it { is_expected.to match_array([project_repository]) }
+ end
+
+ context 'with invalid id' do
+ let(:container_type) { :project }
+ let(:id) { 123456789 }
+
+ it 'raises an error' do
+ expect { subject.execute }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+end
diff --git a/spec/fixtures/api/schemas/registry/repository.json b/spec/fixtures/api/schemas/registry/repository.json
index e0fd4620c43..d0a068b65a7 100644
--- a/spec/fixtures/api/schemas/registry/repository.json
+++ b/spec/fixtures/api/schemas/registry/repository.json
@@ -17,6 +17,9 @@
"path": {
"type": "string"
},
+ "project_id": {
+ "type": "integer"
+ },
"location": {
"type": "string"
},
@@ -28,7 +31,8 @@
},
"destroy_path": {
"type": "string"
- }
+ },
+ "tags": { "$ref": "tags.json" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/clusters/sample_key.key b/spec/fixtures/clusters/sample_key.key
new file mode 100644
index 00000000000..4ddb20b0922
--- /dev/null
+++ b/spec/fixtures/clusters/sample_key.key
@@ -0,0 +1,9 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBAMA5sXIBE0HwgIB40iNidN4PGWzOyLQK0bsdOBNgpEXkDlZBvnak
+OUgAPF+rME4PB0Yl415DabUI40T5UNmlwxcCAwEAAQJAZtY2pSwIFm3JAXIh0cZZ
+iXcAfiJ+YzuqinUOS+eW2sBCAEzjcARlU/o6sFQgtsOi4FOMczAd1Yx8UDMXMmrw
+2QIhAPBgVhJiTF09pdmeFWutCvTJDlFFAQNbrbo2X2x/9WF9AiEAzLgqMKeStSRu
+H9N16TuDrUoO8R+DPqriCwkKrSHaWyMCIFzMhE4inuKcSywBaLmiG4m3GQzs++Al
+A6PRG/PSTpQtAiBxtBg6zdf+JC3GH3zt/dA0/10tL4OF2wORfYQghRzyYQIhAL2l
+0ZQW+yLIZAGrdBFWYEAa52GZosncmzBNlsoTgwE4
+-----END RSA PRIVATE KEY----- \ No newline at end of file
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 7e9bbf5a407..1c41ceb7deb 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -23,6 +23,7 @@ describe Group do
it { is_expected.to have_many(:badges).class_name('GroupBadge') }
it { is_expected.to have_many(:cluster_groups).class_name('Clusters::Group') }
it { is_expected.to have_many(:clusters).class_name('Clusters::Cluster') }
+ it { is_expected.to have_many(:container_repositories) }
describe '#members & #requesters' do
let(:requester) { create(:user) }
diff --git a/spec/requests/api/group_container_repositories_spec.rb b/spec/requests/api/group_container_repositories_spec.rb
new file mode 100644
index 00000000000..0a41e455d01
--- /dev/null
+++ b/spec/requests/api/group_container_repositories_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::GroupContainerRepositories do
+ set(:group) { create(:group, :private) }
+ set(:project) { create(:project, :private, group: group) }
+ let(:reporter) { create(:user) }
+ let(:guest) { create(:user) }
+
+ let(:root_repository) { create(:container_repository, :root, project: project) }
+ let(:test_repository) { create(:container_repository, project: project) }
+
+ let(:users) do
+ {
+ anonymous: nil,
+ guest: guest,
+ reporter: reporter
+ }
+ end
+
+ let(:api_user) { reporter }
+
+ before do
+ group.add_reporter(reporter)
+ group.add_guest(guest)
+
+ stub_feature_flags(container_registry_api: true)
+ stub_container_registry_config(enabled: true)
+
+ root_repository
+ test_repository
+ end
+
+ describe 'GET /groups/:id/registry/repositories' do
+ let(:url) { "/groups/#{group.id}/registry/repositories" }
+
+ subject { get api(url, api_user) }
+
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ it_behaves_like 'returns repositories for allowed users', :reporter, 'group' do
+ let(:object) { group }
+ end
+
+ context 'with invalid group id' do
+ let(:url) { '/groups/123412341234/registry/repositories' }
+
+ it 'returns not found' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/container_registry_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index b64f3ea1081..f1dc4e6f0b2 100644
--- a/spec/requests/api/container_registry_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::ContainerRegistry do
+describe API::ProjectContainerRepositories do
include ExclusiveLeaseHelpers
set(:project) { create(:project, :private) }
@@ -12,6 +12,16 @@ describe API::ContainerRegistry do
let(:root_repository) { create(:container_repository, :root, project: project) }
let(:test_repository) { create(:container_repository, project: project) }
+ let(:users) do
+ {
+ anonymous: nil,
+ developer: developer,
+ guest: guest,
+ maintainer: maintainer,
+ reporter: reporter
+ }
+ end
+
let(:api_user) { maintainer }
before do
@@ -27,57 +37,24 @@ describe API::ContainerRegistry do
test_repository
end
- shared_examples 'being disallowed' do |param|
- context "for #{param}" do
- let(:api_user) { public_send(param) }
-
- it 'returns access denied' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
- context "for anonymous" do
- let(:api_user) { nil }
-
- it 'returns not found' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
describe 'GET /projects/:id/registry/repositories' do
- subject { get api("/projects/#{project.id}/registry/repositories", api_user) }
-
- it_behaves_like 'being disallowed', :guest
-
- context 'for reporter' do
- let(:api_user) { reporter }
-
- it 'returns a list of repositories' do
- subject
+ let(:url) { "/projects/#{project.id}/registry/repositories" }
- expect(json_response.length).to eq(2)
- expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
- root_repository.id, test_repository.id)
- end
+ subject { get api(url, api_user) }
- it 'returns a matching schema' do
- subject
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('registry/repositories')
- end
+ it_behaves_like 'returns repositories for allowed users', :reporter, 'project' do
+ let(:object) { project }
end
end
describe 'DELETE /projects/:id/registry/repositories/:repository_id' do
subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}", api_user) }
- it_behaves_like 'being disallowed', :developer
+ it_behaves_like 'rejected container repository access', :developer, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for maintainer' do
let(:api_user) { maintainer }
@@ -96,7 +73,8 @@ describe API::ContainerRegistry do
describe 'GET /projects/:id/registry/repositories/:repository_id/tags' do
subject { get api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags", api_user) }
- it_behaves_like 'being disallowed', :guest
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for reporter' do
let(:api_user) { reporter }
@@ -124,10 +102,13 @@ describe API::ContainerRegistry do
describe 'DELETE /projects/:id/registry/repositories/:repository_id/tags' do
subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags", api_user), params: params }
- it_behaves_like 'being disallowed', :developer do
+ context 'disallowed' do
let(:params) do
{ name_regex: 'v10.*' }
end
+
+ it_behaves_like 'rejected container repository access', :developer, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
end
context 'for maintainer' do
@@ -191,7 +172,8 @@ describe API::ContainerRegistry do
describe 'GET /projects/:id/registry/repositories/:repository_id/tags/:tag_name' do
subject { get api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags/rootA", api_user) }
- it_behaves_like 'being disallowed', :guest
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for reporter' do
let(:api_user) { reporter }
@@ -222,7 +204,8 @@ describe API::ContainerRegistry do
describe 'DELETE /projects/:id/registry/repositories/:repository_id/tags/:tag_name' do
subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags/rootA", api_user) }
- it_behaves_like 'being disallowed', :reporter
+ it_behaves_like 'rejected container repository access', :reporter, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for developer' do
let(:api_user) { developer }
diff --git a/spec/serializers/analytics_issue_entity_spec.rb b/spec/serializers/analytics_issue_entity_spec.rb
index dd5e43a4b62..c5b03bdd8c1 100644
--- a/spec/serializers/analytics_issue_entity_spec.rb
+++ b/spec/serializers/analytics_issue_entity_spec.rb
@@ -10,12 +10,12 @@ describe AnalyticsIssueEntity do
id: "1",
created_at: "2016-11-12 15:04:02.948604",
author: user,
- name: project.name,
- path: project.namespace
+ project_path: project.path,
+ namespace_path: project.namespace.route.path
}
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'my project') }
let(:request) { EntityRequest.new(entity: :merge_request) }
let(:entity) do
diff --git a/spec/serializers/analytics_issue_serializer_spec.rb b/spec/serializers/analytics_issue_serializer_spec.rb
index c9ffe1c5dad..9cb2ce13d12 100644
--- a/spec/serializers/analytics_issue_serializer_spec.rb
+++ b/spec/serializers/analytics_issue_serializer_spec.rb
@@ -8,7 +8,7 @@ describe AnalyticsIssueSerializer do
end
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'my project') }
let(:resource) do
{
total_time: "172802.724419",
@@ -17,8 +17,8 @@ describe AnalyticsIssueSerializer do
id: "1",
created_at: "2016-11-12 15:04:02.948604",
author: user,
- name: project.name,
- path: project.namespace
+ project_path: project.path,
+ namespace_path: project.namespace.route.path
}
end
diff --git a/spec/serializers/analytics_merge_request_serializer_spec.rb b/spec/serializers/analytics_merge_request_serializer_spec.rb
index 123d7d795ce..a864051b2a3 100644
--- a/spec/serializers/analytics_merge_request_serializer_spec.rb
+++ b/spec/serializers/analytics_merge_request_serializer_spec.rb
@@ -8,7 +8,7 @@ describe AnalyticsMergeRequestSerializer do
end
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'my project') }
let(:resource) do
{
total_time: "172802.724419",
@@ -18,8 +18,8 @@ describe AnalyticsMergeRequestSerializer do
state: 'open',
created_at: "2016-11-12 15:04:02.948604",
author: user,
- name: project.name,
- path: project.namespace
+ project_path: project.path,
+ namespace_path: project.namespace.route.path
}
end
diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
index c11725c63d2..fd24c443288 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -16,7 +16,7 @@ RSpec.shared_context 'GroupPolicy context' do
read_group_merge_requests
]
end
- let(:reporter_permissions) { [:admin_label] }
+ let(:reporter_permissions) { %i[admin_label read_container_image] }
let(:developer_permissions) { [:admin_milestone] }
let(:maintainer_permissions) do
%i[
diff --git a/spec/support/shared_examples/container_repositories_shared_examples.rb b/spec/support/shared_examples/container_repositories_shared_examples.rb
new file mode 100644
index 00000000000..946b130fca2
--- /dev/null
+++ b/spec/support/shared_examples/container_repositories_shared_examples.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+shared_examples 'rejected container repository access' do |user_type, status|
+ context "for #{user_type}" do
+ let(:api_user) { users[user_type] }
+
+ it "returns #{status}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+ end
+end
+
+shared_examples 'returns repositories for allowed users' do |user_type, scope|
+ context "for #{user_type}" do
+ it 'returns a list of repositories' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
+ root_repository.id, test_repository.id)
+ expect(response.body).not_to include('tags')
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
+
+ context 'with tags param' do
+ let(:url) { "/#{scope}s/#{object.id}/registry/repositories?tags=true" }
+
+ before do
+ stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA latest), with_manifest: true)
+ stub_container_registry_tags(repository: test_repository.path, tags: %w(rootA latest), with_manifest: true)
+ end
+
+ it 'returns a list of repositories and their tags' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
+ root_repository.id, test_repository.id)
+ expect(response.body).to include('tags')
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
+ end
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index d8193af1310..acf1a4d8652 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -996,10 +996,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.67.0.tgz#c7b94eca13b99fd3aaa737fb6dcc0abc41d3c579"
integrity sha512-hJOmWEs6RkjzyKkb1vc9wwKGZIBIP0coHkxu/KgOoxhBVudpGk4CH7xJ6UuB2TKpb0SEh5CC1CzRZfBYaFhsaA==
-"@gitlab/ui@5.12.1":
- version "5.12.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.12.1.tgz#70035747cec96a729e012924ab2d3e3b6067a558"
- integrity sha512-W4rvZj2Fab1UpXR0Wyi7wSvj+5Ko+TWHibC/q/FSRHMsbeSLq77lljd7rQWeXXNMBvEKwr4NqSmckWsjaSOLfw==
+"@gitlab/ui@5.14.0":
+ version "5.14.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.14.0.tgz#850214cfc6bb57f7ce672dc1cc60ea3d39ad41f3"
+ integrity sha512-JXUmk+hT4Rj2GBh0xAF43dYeloBEDX22rgeaDU6/RzD3JEA353yEm2+HOsBjPkQFDAh6Zp7OZSBuhDFrQe8sbg==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"