Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2019-11-04 15:07:36 +00:00
parent 2494b608a4
commit aa542224bb
32 changed files with 319 additions and 78 deletions

View File

@ -1,5 +1,12 @@
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)

View File

@ -1,4 +1,4 @@
/* 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) {

View File

@ -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;
}
}
}

View File

@ -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 {

View File

@ -1,34 +1,38 @@
# 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 project_type?
type == :project
def valid_subject_type?
VALID_SUBJECTS.include?(@subject.class)
end
def project
Project.find(id)
def project_repositories
return unless @subject.container_registry_enabled
@subject.container_repositories
end
def group
Group.find(id)
def group_repositories
ContainerRepository.for_group_and_its_subgroups(@subject)
end
def authorized?
Ability.allowed?(@user, :read_container_image, @subject)
end
end

View File

@ -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)})"

View File

@ -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

View File

@ -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
{

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1 @@
= _("These variables are configured in the parent group settings, and will be active in the current project in addition to the project variables.")

View File

@ -0,0 +1,5 @@
%h5
= _('Group variables (inherited)')
%p
= render "ci/group_variables/content"

View File

@ -0,0 +1,13 @@
- 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

View File

@ -0,0 +1,5 @@
.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')

View File

@ -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'

View File

@ -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?

View File

@ -0,0 +1,5 @@
---
title: Show inherited group variables in project view
merge_request: 18759
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add links to associated releases on the Milestones page
merge_request: 16558
author:
type: added

View File

@ -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

View File

@ -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
#

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -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]

View File

@ -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]

View File

@ -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 ""

View File

@ -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

View File

@ -0,0 +1,60 @@
# 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

View File

@ -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
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)
it { is_expected.to match_array([project_repository]) }
end
context 'with invalid subject_type' do
let(:subject_object) { "invalid type" }
it { expect { subject }.to raise_exception('invalid subject_type') }
end
end
context 'with unauthorized user' do
subject { described_class.new(user: guest, subject: group).execute }
it { is_expected.to be nil }
end
end
end

View File

@ -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

View File

@ -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) }

0
vendor/gitignore/C++.gitignore vendored Executable file → Normal file
View File

0
vendor/gitignore/Java.gitignore vendored Executable file → Normal file
View File