diff --git a/CHANGELOG-EE.md b/CHANGELOG-EE.md
index cd501f8583a..9fa018b9719 100644
--- a/CHANGELOG-EE.md
+++ b/CHANGELOG-EE.md
@@ -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)
diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js
index 7a60ab1380f..044d703630e 100644
--- a/app/assets/javascripts/zen_mode.js
+++ b/app/assets/javascripts/zen_mode.js
@@ -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) {
diff --git a/app/assets/stylesheets/framework/ci_variable_list.scss b/app/assets/stylesheets/framework/ci_variable_list.scss
index 28d7492b99c..cae7b9b5e46 100644
--- a/app/assets/stylesheets/framework/ci_variable_list.scss
+++ b/app/assets/stylesheets/framework/ci_variable_list.scss
@@ -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;
+    }
+  }
+}
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index 00d84df1650..b399662997c 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -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 {
diff --git a/app/finders/container_repositories_finder.rb b/app/finders/container_repositories_finder.rb
index eb91d7f825b..34921df840b 100644
--- a/app/finders/container_repositories_finder.rb
+++ b/app/finders/container_repositories_finder.rb
@@ -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
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index e769734f27b..60165e0d0a4 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -170,6 +170,15 @@ module MilestonesHelper
     content.join('
').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)})"
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index 7a3a79cead0..152aa7b3218 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -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
diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb
index 7d766e1f25c..61c62929b61 100644
--- a/app/models/global_milestone.rb
+++ b/app/models/global_milestone.rb
@@ -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
     {
diff --git a/app/models/project.rb b/app/models/project.rb
index 245d29554a3..2cb5af382b6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -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.
diff --git a/app/models/release.rb b/app/models/release.rb
index 1261402712f..ec40e8ec3e2 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -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
diff --git a/app/views/ci/group_variables/_content.html.haml b/app/views/ci/group_variables/_content.html.haml
new file mode 100644
index 00000000000..db5f1021f57
--- /dev/null
+++ b/app/views/ci/group_variables/_content.html.haml
@@ -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.")
diff --git a/app/views/ci/group_variables/_header.html.haml b/app/views/ci/group_variables/_header.html.haml
new file mode 100644
index 00000000000..71d123ec9f2
--- /dev/null
+++ b/app/views/ci/group_variables/_header.html.haml
@@ -0,0 +1,5 @@
+%h5
+  = _('Group variables (inherited)')
+
+%p
+  = render "ci/group_variables/content"
diff --git a/app/views/ci/group_variables/_index.html.haml b/app/views/ci/group_variables/_index.html.haml
new file mode 100644
index 00000000000..c350ba5caf7
--- /dev/null
+++ b/app/views/ci/group_variables/_index.html.haml
@@ -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
diff --git a/app/views/ci/group_variables/_variable_header.html.haml b/app/views/ci/group_variables/_variable_header.html.haml
new file mode 100644
index 00000000000..1a3168cf781
--- /dev/null
+++ b/app/views/ci/group_variables/_variable_header.html.haml
@@ -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')
diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml
index 94102b4dcd0..7ae5c48b93c 100644
--- a/app/views/ci/variables/_index.html.haml
+++ b/app/views/ci/variables/_index.html.haml
@@ -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'
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index e99aa3f1ee4..b324f35c338 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -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
+                •
+            - if total_count > recent_releases.count
+              •
+              = 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?
diff --git a/changelogs/unreleased/24172-group-vars.yml b/changelogs/unreleased/24172-group-vars.yml
new file mode 100644
index 00000000000..14f604de1a4
--- /dev/null
+++ b/changelogs/unreleased/24172-group-vars.yml
@@ -0,0 +1,5 @@
+---
+title: Show inherited group variables in project view
+merge_request: 18759
+author:
+type: added
diff --git a/changelogs/unreleased/nfriend-add-release-to-milestone-list-page.yml b/changelogs/unreleased/nfriend-add-release-to-milestone-list-page.yml
new file mode 100644
index 00000000000..46bffa3476d
--- /dev/null
+++ b/changelogs/unreleased/nfriend-add-release-to-milestone-list-page.yml
@@ -0,0 +1,5 @@
+---
+title: Add links to associated releases on the Milestones page
+merge_request: 16558
+author:
+type: added
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 94fd71aaa33..43e3315a870 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -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/
+      # app_name: gitlab.com # Environment name of your GitLab instance
+      # instance_id: INSTANCE_ID
 
   #
   # 2. GitLab CI settings
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 5e94a0716fa..12ba56a15e9 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -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
 #
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index bc0b6da45a9..cff797549ba 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -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.
+
+
 
 ## Priority of environment variables
 
diff --git a/doc/ci/variables/img/inherited_group_variables_v12_5.png b/doc/ci/variables/img/inherited_group_variables_v12_5.png
new file mode 100644
index 00000000000..f9043df051c
Binary files /dev/null and b/doc/ci/variables/img/inherited_group_variables_v12_5.png differ
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
index fd24662cc9a..d1aaafec8aa 100644
--- a/lib/api/group_container_repositories.rb
+++ b/lib/api/group_container_repositories.rb
@@ -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]
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 2a05974509a..c7731b70f39 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -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]
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f95f329442c..dde99a8583a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -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 ""
 
diff --git a/spec/features/milestones/user_views_milestones_spec.rb b/spec/features/milestones/user_views_milestones_spec.rb
index 0b51ca12997..09378cab5e3 100644
--- a/spec/features/milestones/user_views_milestones_spec.rb
+++ b/spec/features/milestones/user_views_milestones_spec.rb
@@ -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
diff --git a/spec/features/project_group_variables_spec.rb b/spec/features/project_group_variables_spec.rb
new file mode 100644
index 00000000000..c1f1c442937
--- /dev/null
+++ b/spec/features/project_group_variables_spec.rb
@@ -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
diff --git a/spec/finders/container_repositories_finder_spec.rb b/spec/finders/container_repositories_finder_spec.rb
index deec62d6598..43b82faa9a3 100644
--- a/spec/finders/container_repositories_finder_spec.rb
+++ b/spec/finders/container_repositories_finder_spec.rb
@@ -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
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index eea539746a5..0a3065140bf 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -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
diff --git a/spec/requests/api/group_container_repositories_spec.rb b/spec/requests/api/group_container_repositories_spec.rb
index 0a41e455d01..0b75b056fb7 100644
--- a/spec/requests/api/group_container_repositories_spec.rb
+++ b/spec/requests/api/group_container_repositories_spec.rb
@@ -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) }
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
old mode 100755
new mode 100644
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
old mode 100755
new mode 100644