Commit aa542224 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 2494b608
Please view this file on the master branch, on stable branches it's out of date.
## 12.4.2
### Fixed (1 change)
- Fix feature flag check for productivity analytics. !19025
## 12.4.1
### Security (6 changes)
......
/* eslint-disable func-names, consistent-return, camelcase, class-methods-use-this */
/* eslint-disable consistent-return, camelcase, class-methods-use-this */
// Zen Mode (full screen) textarea
//
......@@ -47,26 +47,16 @@ export default class ZenMode {
e.preventDefault();
return $(e.currentTarget).trigger('zen_mode:leave');
});
$(document).on(
'zen_mode:enter',
(function(_this) {
return function(e) {
return _this.enter(
$(e.target)
.closest('.md-area')
.find('.zen-backdrop'),
);
};
})(this),
);
$(document).on(
'zen_mode:leave',
(function(_this) {
return function() {
return _this.exit();
};
})(this),
);
$(document).on('zen_mode:enter', e => {
this.enter(
$(e.target)
.closest('.md-area')
.find('.zen-backdrop'),
);
});
$(document).on('zen_mode:leave', () => {
this.exit();
});
$(document).on('keydown', e => {
// Esc
if (e.keyCode === 27) {
......
......@@ -99,3 +99,13 @@
color: $gl-text-color-disabled;
}
}
.group-variable-list {
color: $gray-700;
.table-section:not(:first-child) {
@include media-breakpoint-down(sm) {
border-top: hidden;
}
}
}
......@@ -30,7 +30,8 @@ $status-box-line-height: 26px;
margin-bottom: $gl-padding-4;
}
.milestone-progress {
.milestone-progress,
.milestone-release-links {
a {
color: $blue-600;
}
......@@ -238,10 +239,6 @@ $status-box-line-height: 26px;
}
}
.milestone-range {
color: $gl-text-color-tertiary;
}
@include media-breakpoint-down(xs) {
.milestone-banner-text,
.milestone-banner-link {
......
# 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
VALID_SUBJECTS = [Group, Project].freeze
def initialize(user:, subject:)
@user = user
@subject = subject
end
def execute
if project_type?
project.container_repositories
else
group.container_repositories
end
raise ArgumentError, "invalid subject_type" unless valid_subject_type?
return unless authorized?
return project_repositories if @subject.is_a?(Project)
return group_repositories if @subject.is_a?(Group)
end
private
attr_reader :id, :type
def valid_subject_type?
VALID_SUBJECTS.include?(@subject.class)
end
def project_repositories
return unless @subject.container_registry_enabled
def project_type?
type == :project
@subject.container_repositories
end
def project
Project.find(id)
def group_repositories
ContainerRepository.for_group_and_its_subgroups(@subject)
end
def group
Group.find(id)
def authorized?
Ability.allowed?(@user, :read_container_image, @subject)
end
end
......@@ -170,6 +170,15 @@ module MilestonesHelper
content.join('<br />').html_safe
end
def recent_releases_with_counts(milestone)
total_count = milestone.releases.size
return [[], 0, 0] if total_count == 0
recent_releases = milestone.releases.recent.to_a
more_count = total_count - recent_releases.size
[recent_releases, total_count, more_count]
end
def milestone_tooltip_due_date(milestone)
if milestone.due_date
"#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone.due_date, milestone.start_date)})"
......
......@@ -12,6 +12,9 @@ class ContainerRepository < ApplicationRecord
scope :ordered, -> { order(:name) }
scope :with_api_entity_associations, -> { preload(project: [:route, { namespace: :route }]) }
scope :for_group_and_its_subgroups, ->(group) do
where(project_id: Project.for_group_and_its_subgroups(group).with_container_registry.select(:id))
end
# rubocop: disable CodeReuse/ServiceClass
def registry
......
......@@ -11,7 +11,7 @@ class GlobalMilestone
delegate :title, :state, :due_date, :start_date, :participants, :project,
:group, :expires_at, :closed?, :iid, :group_milestone?, :safe_title,
:milestoneish_id, :resource_parent, to: :milestone
:milestoneish_id, :resource_parent, :releases, to: :milestone
def to_hash
{
......
......@@ -395,6 +395,7 @@ class Project < ApplicationRecord
scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') }
scope :with_statistics, -> { includes(:statistics) }
scope :with_shared_runners, -> { where(shared_runners_enabled: true) }
scope :with_container_registry, -> { where(container_registry_enabled: true) }
scope :inside_path, ->(path) do
# We need routes alias rs for JOIN so it does not conflict with
# includes(:route) which we use in ProjectsFinder.
......
......@@ -28,12 +28,16 @@ class Release < ApplicationRecord
scope :sorted, -> { order(released_at: :desc) }
scope :preloaded, -> { includes(project: :namespace) }
scope :with_project_and_namespace, -> { includes(project: :namespace) }
scope :recent, -> { sorted.limit(MAX_NUMBER_TO_DISPLAY) }
delegate :repository, to: :project
after_commit :create_evidence!, on: :create
after_commit :notify_new_release, on: :create
MAX_NUMBER_TO_DISPLAY = 3
def to_param
CGI.escape(tag)
end
......
= _("These variables are configured in the parent group settings, and will be active in the current project in addition to the project variables.")
%h5
= _('Group variables (inherited)')
%p
= render "ci/group_variables/content"
- variables = @project.group.self_and_ancestors.map(&:variables).flatten
.row
.col-lg-12
.group-variable-list
= render 'ci/group_variables/variable_header'
- variables.each do |variable|
.group-variable-row.d-flex.w-100.border-bottom.pt-2.pb-2
.table-section.section-40.append-right-10.key
= variable.key
.table-section.section-40.append-right-10
%a.group-origin-link{ href: group_settings_ci_cd_path(variable.group) }
= variable.group.name
.group-variable-keys.d-flex.w-100.align-items-center.pb-2.border-bottom
.bold.table-section.section-40.append-right-10
= s_('Key')
.bold.table-section.section-40.append-right-10
= s_('Origin')
......@@ -24,3 +24,8 @@
= n_('Hide value', 'Hide values', @variables.size)
- else
= n_('Reveal value', 'Reveal values', @variables.size)
- if !@group && @project.group
.settings-header.border-top.prepend-top-20
= render 'ci/group_variables/header'
.settings-content.pr-0
= render 'ci/group_variables/index'
......@@ -12,8 +12,20 @@
- if @project || milestone.is_a?(GlobalMilestone) || milestone.group_milestone?
- if milestone.due_date || milestone.start_date
.milestone-range.append-bottom-5
.text-tertiary.append-bottom-5
= milestone_date_range(milestone)
- recent_releases, total_count, more_count = recent_releases_with_counts(milestone)
- unless total_count.zero?
.text-tertiary.append-bottom-5.milestone-release-links
= icon('rocket')
= n_('Release', 'Releases', total_count)
- recent_releases.each do |release|
= link_to release.name, project_releases_path(release.project, anchor: release.tag)
- unless release == recent_releases.last
&bull;
- if total_count > recent_releases.count
&bull;
= link_to n_('%{count} more release', '%{count} more releases', more_count) % { count: more_count }, project_releases_path(milestone.project)
%div
= render('shared/milestone_expired', milestone: milestone)
- if milestone.group_milestone?
......
---
title: Show inherited group variables in project view
merge_request: 18759
author:
type: added
---
title: Add links to associated releases on the Milestones page
merge_request: 16558
author:
type: added
......@@ -467,6 +467,13 @@ production: &base
# enabled: true
# primary_api_url: http://localhost:5000/ # internal address to the primary registry, will be used by GitLab to directly communicate with primary registry API
## Feature Flag https://docs.gitlab.com/ee/user/project/operations/feature_flags.html
feature_flags:
unleash:
# enabled: false
# url: https://gitlab.com/api/v4/feature_flags/unleash/<project_id>
# app_name: gitlab.com # Environment name of your GitLab instance
# instance_id: INSTANCE_ID
#
# 2. GitLab CI settings
......
......@@ -308,6 +308,13 @@ Gitlab.ee do
Settings.geo.registry_replication['enabled'] ||= false
end
#
# Unleash
#
Settings['feature_flags'] ||= Settingslogic.new({})
Settings.feature_flags['unleash'] ||= Settingslogic.new({})
Settings.feature_flags.unleash['enabled'] = false if Settings.feature_flags.unleash['enabled'].nil?
#
# External merge request diffs
#
......
......@@ -357,7 +357,12 @@ Group-level variables can be added by:
1. Inputing variable types, keys, and values in the **Variables** section.
Any variables of [subgroups](../../user/group/subgroups/index.md) will be inherited recursively.
Once you set them, they will be available for all subsequent pipelines.
Once you set them, they will be available for all subsequent pipelines. Any group-level user defined variables can be viewed in projects by:
1. Navigating to the project's **Settings > CI/CD** page.
1. Expanding the **Variables** section.
![CI/CD settings - inherited variables](img/inherited_group_variables_v12_5.png)
## Priority of environment variables
......
......@@ -23,7 +23,7 @@ module API
end
get ':id/registry/repositories' do
repositories = ContainerRepositoriesFinder.new(
id: user_group.id, container_type: :group
user: current_user, subject: user_group
).execute
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags]
......
......@@ -24,7 +24,7 @@ module API
end
get ':id/registry/repositories' do
repositories = ContainerRepositoriesFinder.new(
id: user_project.id, container_type: :project
user: current_user, subject: user_project
).execute
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags]
......
......@@ -210,6 +210,11 @@ msgstr ""
msgid "%{count} more assignees"
msgstr ""
msgid "%{count} more release"
msgid_plural "%{count} more releases"
msgstr[0] ""
msgstr[1] ""
msgid "%{count} of %{required} approvals from %{name}"
msgstr ""
......@@ -8336,6 +8341,9 @@ msgstr ""
msgid "Group pipeline minutes were successfully reset."
msgstr ""
msgid "Group variables (inherited)"
msgstr ""
msgid "Group was successfully updated."
msgstr ""
......@@ -9537,6 +9545,9 @@ msgstr ""
msgid "June"
msgstr ""
msgid "Key"
msgstr ""
msgid "Key (PEM)"
msgstr ""
......@@ -11601,6 +11612,9 @@ msgstr ""
msgid "Or you can choose one of the suggested colors below"
msgstr ""
msgid "Origin"
msgstr ""
msgid "Other Labels"
msgstr ""
......@@ -13794,7 +13808,9 @@ msgid "Related merge requests"
msgstr ""
msgid "Release"
msgstr ""
msgid_plural "Releases"
msgstr[0] ""
msgstr[1] ""
msgid "Release notes"
msgstr ""
......@@ -16933,6 +16949,9 @@ msgstr ""
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr ""
msgid "These variables are configured in the parent group settings, and will be active in the current project in addition to the project variables."
msgstr ""
msgid "They can be managed using the %{link}."
msgstr ""
......
......@@ -34,4 +34,31 @@ describe "User views milestones" do
.and have_content(closed_issue.title)
end
end
context "with associated releases" do
set(:first_release) { create(:release, project: project, name: "The first release", milestones: [milestone], released_at: Time.zone.parse('2019-10-07')) }
context "with a single associated release" do
it "shows the associated release" do
expect(page).to have_content("Release #{first_release.name}")
expect(page).to have_link(first_release.name, href: project_releases_path(project, anchor: first_release.tag))
end
end
context "with lots of associated releases" do
set(:second_release) { create(:release, project: project, name: "The second release", milestones: [milestone], released_at: first_release.released_at + 1.day) }
set(:third_release) { create(:release, project: project, name: "The third release", milestones: [milestone], released_at: second_release.released_at + 1.day) }
set(:fourth_release) { create(:release, project: project, name: "The fourth release", milestones: [milestone], released_at: third_release.released_at + 1.day) }
set(:fifth_release) { create(:release, project: project, name: "The fifth release", milestones: [milestone], released_at: fourth_release.released_at + 1.day) }
it "shows the associated releases and the truncation text" do
expect(page).to have_content("Releases #{fifth_release.name}#{fourth_release.name}#{third_release.name} • 2 more releases")
expect(page).to have_link(fifth_release.name, href: project_releases_path(project, anchor: fifth_release.tag))
expect(page).to have_link(fourth_release.name, href: project_releases_path(project, anchor: fourth_release.tag))
expect(page).to have_link(third_release.name, href: project_releases_path(project, anchor: third_release.tag))
expect(page).to have_link("2 more releases", href: project_releases_path(project))
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'Project group variables', :js do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:subgroup_nested) { create(:group, parent: subgroup) }
let(:project) { create(:project, group: group) }
let(:project2) { create(:project, group: subgroup) }
let(:project3) { create(:project, group: subgroup_nested) }
let(:key1) { 'test_key' }
let(:key2) { 'test_key2' }
let(:key3) { 'test_key3' }
let!(:ci_variable) { create(:ci_group_variable, group: group, key: key1) }
let!(:ci_variable2) { create(:ci_group_variable, group: subgroup, key: key2) }
let!(:ci_variable3) { create(:ci_group_variable, group: subgroup_nested, key: key3) }
let(:project_path) { project_settings_ci_cd_path(project) }
let(:project2_path) { project_settings_ci_cd_path(project2) }
let(:project3_path) { project_settings_ci_cd_path(project3) }
before do
sign_in(user)
project.add_maintainer(user)
group.add_owner(user)
end
it 'project in group shows inherited vars from ancestor group' do
visit project_path
expect(page).to have_content(key1)
expect(page).to have_content(group.name)
end
it 'project in subgroup shows inherited vars from all ancestor groups' do
visit project2_path
expect(page).to have_content(key1)
expect(page).to have_content(key2)
expect(page).to have_content(group.name)
expect(page).to have_content(subgroup.name)
end
it 'project in nested subgroup shows inherited vars from all ancestor groups' do
visit project3_path
expect(page).to have_content(key1)
expect(page).to have_content(key2)
expect(page).to have_content(key3)
expect(page).to have_content(group.name)
expect(page).to have_content(subgroup.name)
expect(page).to have_content(subgroup_nested.name)
end
it 'project origin keys link to ancestor groups ci_cd settings' do
visit project_path
find('.group-origin-link').click
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq(key1)
end
end
end
......@@ -3,42 +3,50 @@
require 'spec_helper'
describe ContainerRepositoriesFinder do
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
let(:project_repository) { create(:container_repository, project: project) }
before do
group.add_reporter(reporter)
project.add_reporter(reporter)
end
describe '#execute' do
let(:id) { nil }
context 'with authorized user' do
subject { described_class.new(user: reporter, subject: subject_object).execute }
subject { described_class.new(id: id, container_type: container_type).execute }
context 'when subject_type is group' do
let(:subject_object) { group }
let(:other_project) { create(:project, group: group) }
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(:other_repository) do
create(:container_repository, name: 'test_repository2', project: other_project)
it { is_expected.to match_array([project_repository, other_repository]) }
end
let(:container_type) { :group }
let(:id) { group.id }
context 'when subject_type is project' do
let(:subject_object) { project }
it { is_expected.to match_array([project_repository, other_repository]) }
end
it { is_expected.to match_array([project_repository]) }
end
context 'when container_type is project' do
let(:container_type) { :project }
let(:id) { project.id }
context 'with invalid subject_type' do
let(:subject_object) { "invalid type" }
it { is_expected.to match_array([project_repository]) }
it { expect { subject }.to raise_exception('invalid subject_type') }
end
end
context 'with invalid id' do
let(:container_type) { :project }
let(:id) { 123456789 }
context 'with unauthorized user' do
subject { described_class.new(user: guest, subject: group).execute }
it 'raises an error' do
expect { subject.execute }.to raise_error(ActiveRecord::RecordNotFound)
end
it { is_expected.to be nil }
end
end
end
......@@ -235,4 +235,36 @@ describe ContainerRepository do
expect(repository).not_to be_persisted
end
end
describe '.for_group_and_its_subgroups' do
subject { described_class.for_group_and_its_subgroups(test_group) }
context 'in a group' do
let(:test_group) { group }
it { is_expected.to contain_exactly(repository) }
end
context 'with a subgroup' do
let(:test_group) { create(:group) }
let(:another_project) { create(:project, path: 'test', group: test_group) }
let(:another_repository) do
create(:container_repository, name: 'my_image', project: another_project)
end
before do
group.parent = test_group
group.save
end
it { is_expected.to contain_exactly(repository, another_repository) }
end
context 'group without container_repositories' do
let(:test_group) { create(:group) }
it { is_expected.to eq([]) }
end
end
end
......@@ -3,10 +3,10 @@
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_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, :private, group: group) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let(:root_repository) { create(:container_repository, :root, project: project) }
let(:test_repository) { create(:container_repository, project: project) }
......
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment