diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 2bb34b7ed4b2d95af0cf327e552d6ee983fc3587..78ddbedf25bfb2d5d4f8c77ba46199c758d40a4a 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -238,6 +238,7 @@
 
   .group-path {
     color: $gl-gray-400;
+<<<<<<< HEAD
   }
 }
 
@@ -248,6 +249,8 @@
 
   .project-path {
     color: $gl-gray-400;
+=======
+>>>>>>> upstream/master
   }
 }
 
diff --git a/app/models/concerns/project_services_loggable.rb b/app/models/concerns/project_services_loggable.rb
index 248a21f357878e0244845079e0d51c0858cff6be..fecd77cdc985a195131bb21c52ef4c673713ffb0 100644
--- a/app/models/concerns/project_services_loggable.rb
+++ b/app/models/concerns/project_services_loggable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module ProjectServicesLoggable
   def log_info(message, params = {})
     message = build_message(message, params)
diff --git a/app/models/hooks/active_hook_filter.rb b/app/models/hooks/active_hook_filter.rb
index ea046bea368206dc16a4668ba7d90a4da80a0a8f..283e2d680f4b2c1b03d68289a9cd4a3071a09e09 100644
--- a/app/models/hooks/active_hook_filter.rb
+++ b/app/models/hooks/active_hook_filter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class ActiveHookFilter
   def initialize(hook)
     @hook = hook
diff --git a/app/serializers/status_entity.rb b/app/serializers/detailed_status_entity.rb
similarity index 74%
rename from app/serializers/status_entity.rb
rename to app/serializers/detailed_status_entity.rb
index 306c30f0323b8529d6603274cfa095b440271989..c772c807f76d121551972f1bc12ce34edf31a5fd 100644
--- a/app/serializers/status_entity.rb
+++ b/app/serializers/detailed_status_entity.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-class StatusEntity < Grape::Entity
+class DetailedStatusEntity < Grape::Entity
   include RequestAwareEntity
 
   expose :icon, :text, :label, :group
@@ -8,6 +8,14 @@ class StatusEntity < Grape::Entity
   expose :has_details?, as: :has_details
   expose :details_path
 
+  expose :illustration do |status|
+    begin
+      status.illustration
+    rescue NotImplementedError
+      # ignored
+    end
+  end
+
   expose :favicon do |status|
     Gitlab::Favicon.status_overlay(status.favicon)
   end
diff --git a/app/serializers/job_entity.rb b/app/serializers/job_entity.rb
index 7bc1d87dea5a7a3646f87e750bdf3aaf58543b34..26b29993fecee6ffc671b50604cb01f506e5b143 100644
--- a/app/serializers/job_entity.rb
+++ b/app/serializers/job_entity.rb
@@ -27,7 +27,7 @@ class JobEntity < Grape::Entity
   expose :playable?, as: :playable
   expose :created_at
   expose :updated_at
-  expose :detailed_status, as: :status, with: StatusEntity
+  expose :detailed_status, as: :status, with: DetailedStatusEntity
   expose :callout_message, if: -> (*) { failed? && !build.script_failure? }
   expose :recoverable, if: -> (*) { failed? }
 
diff --git a/app/serializers/job_group_entity.rb b/app/serializers/job_group_entity.rb
index 0941a9d36be9e43a6147435b1a90bb1f7ec5431e..0db7624b3f76adb8addef48bf9b0075739f18fa0 100644
--- a/app/serializers/job_group_entity.rb
+++ b/app/serializers/job_group_entity.rb
@@ -5,7 +5,7 @@ class JobGroupEntity < Grape::Entity
 
   expose :name
   expose :size
-  expose :detailed_status, as: :status, with: StatusEntity
+  expose :detailed_status, as: :status, with: DetailedStatusEntity
   expose :jobs, with: JobEntity
 
   private
diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb
index 6cf1925adda6c17f30bcc8c251409b3f4f0ef5a3..aef838409e0c718da3a1449f500142be6d8ef8c2 100644
--- a/app/serializers/pipeline_entity.rb
+++ b/app/serializers/pipeline_entity.rb
@@ -30,7 +30,7 @@ class PipelineEntity < Grape::Entity
   end
 
   expose :details do
-    expose :detailed_status, as: :status, with: StatusEntity
+    expose :detailed_status, as: :status, with: DetailedStatusEntity
     expose :duration
     expose :finished_at
   end
diff --git a/app/serializers/stage_entity.rb b/app/serializers/stage_entity.rb
index 00e6d32ee3a9b21dd61e9e3ce04326e2aa7c2daa..ca8fa7e78772f6a8a7fb4561d6938021f26bf4c6 100644
--- a/app/serializers/stage_entity.rb
+++ b/app/serializers/stage_entity.rb
@@ -19,7 +19,7 @@ class StageEntity < Grape::Entity
     latest_statuses
   end
 
-  expose :detailed_status, as: :status, with: StatusEntity
+  expose :detailed_status, as: :status, with: DetailedStatusEntity
 
   expose :path do |stage|
     project_pipeline_path(
diff --git a/app/services/emails/base_service.rb b/app/services/emails/base_service.rb
index ba7b689a9af62a29e448879e3eaf8506dad0b98b..988215ffc78aaad3236cb2b8a3a704b308b2e03a 100644
--- a/app/services/emails/base_service.rb
+++ b/app/services/emails/base_service.rb
@@ -2,6 +2,8 @@
 
 module Emails
   class BaseService
+    attr_reader :current_user
+
     def initialize(current_user, params = {})
       @current_user, @params = current_user, params.dup
       @user = params.delete(:user)
diff --git a/app/services/emails/create_service.rb b/app/services/emails/create_service.rb
index 224ee7018ad42d50f8334145bbcfbcad20aad432..fb7d234ccae0207c2a7b7bbc15dd5cc7afcc1f73 100644
--- a/app/services/emails/create_service.rb
+++ b/app/services/emails/create_service.rb
@@ -5,7 +5,12 @@ module Emails
     prepend ::EE::Emails::CreateService
 
     def execute(extra_params = {})
-      @user.emails.create(@params.merge(extra_params))
+      skip_confirmation = @params.delete(:skip_confirmation)
+
+      email = @user.emails.create(@params.merge(extra_params))
+
+      email&.confirm if skip_confirmation && current_user.admin?
+      email
     end
   end
 end
diff --git a/app/validators/branch_filter_validator.rb b/app/validators/branch_filter_validator.rb
index ef482aaaa6315cf74f1a9a50daa82f75c731ac68..6a0899be850b6d75b3989a007b8143808c0de862 100644
--- a/app/validators/branch_filter_validator.rb
+++ b/app/validators/branch_filter_validator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 # BranchFilterValidator
 #
 # Custom validator for branch names. Squishes whitespace and ignores empty
diff --git a/app/validators/js_regex_validator.rb b/app/validators/js_regex_validator.rb
index a515af7b919d4793f8101493b92dad3690052f99..be715967b4a20dbfccf36d8fb97142e1fcfd0c31 100644
--- a/app/validators/js_regex_validator.rb
+++ b/app/validators/js_regex_validator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class JsRegexValidator < ActiveModel::EachValidator
   def validate_each(record, attribute, value)
     return true if value.blank?
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 5623f0f590a50b51089e17f09fc84b8282b2cac7..78a1d1a0553c2c47b299eb419d6396062c9deeb8 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -11,5 +11,5 @@
       = render "events/event/note", event: event
     - else
       = render "events/event/common", event: event
-- elsif @user.include_private_contributions?
+- elsif @user&.include_private_contributions?
   = render "events/event/private", event: event
diff --git a/changelogs/unreleased/51112-add-status-illustration-in-job-api.yml b/changelogs/unreleased/51112-add-status-illustration-in-job-api.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fdc75e2882480da2ba171ea2d26c6dc9e7be8665
--- /dev/null
+++ b/changelogs/unreleased/51112-add-status-illustration-in-job-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add empty state illustration information in job API
+merge_request: 21532
+author:
+type: other
diff --git a/changelogs/unreleased/frozen-string-enable-vestigial.yml b/changelogs/unreleased/frozen-string-enable-vestigial.yml
new file mode 100644
index 0000000000000000000000000000000000000000..55313ff0fccf0670a9bb0979a0272337a1aa61f3
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-enable-vestigial.yml
@@ -0,0 +1,5 @@
+---
+title: Enable frozen string in vestigial files
+merge_request:
+author: gfyoung
+type: performance
diff --git a/changelogs/unreleased/sh-support-adding-confirmed-emails.yml b/changelogs/unreleased/sh-support-adding-confirmed-emails.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1b64a1c62dc6951f4a61fd757a6222be171372f3
--- /dev/null
+++ b/changelogs/unreleased/sh-support-adding-confirmed-emails.yml
@@ -0,0 +1,5 @@
+---
+title: Add ability to skip user email confirmation with API
+merge_request: 21630
+author:
+type: added
diff --git a/db/importers/common_metrics_importer.rb b/db/importers/common_metrics_importer.rb
index 01fbbd6866b99b910a2cac94919940a780a29ee5..6302394d7a6b173f2995ab898bb92250923799b4 100644
--- a/db/importers/common_metrics_importer.rb
+++ b/db/importers/common_metrics_importer.rb
@@ -35,8 +35,8 @@ module Importers
 
     attr_reader :content
 
-    def initialize(file = 'config/prometheus/common_metrics.yml')
-      @content = YAML.load_file(file)
+    def initialize(filename = 'common_metrics.yml')
+      @content = YAML.load_file(Rails.root.join('config', 'prometheus', filename))
     end
 
     def execute
diff --git a/doc/api/users.md b/doc/api/users.md
index f2e6486c080a8436065f1e2dd6b1c83c1672bdb1..389f5101d63c73b70a650d2df1afd70a04390737 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -977,6 +977,7 @@ Parameters:
 
 - `id` (required)    - id of specified user
 - `email` (required) - email address
+- `skip_confirmation` (optional) - Skip confirmation and assume e-mail is verified - true or false (default)
 
 ## Delete email for current user
 
diff --git a/lib/api/users.rb b/lib/api/users.rb
index eea79cf33b65eb3e65a2c94185a57a274647f01f..661e070896b984e6e4e584f6ebfa07b5dc7bcf9a 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -367,6 +367,7 @@ module API
       params do
         requires :id, type: Integer, desc: 'The ID of the user'
         requires :email, type: String, desc: 'The email of the user'
+        optional :skip_confirmation, type: Boolean, desc: 'Skip confirmation of email and assume it is verified'
       end
       post ":id/emails" do
         authenticated_as_admin!
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 751919f95017f487eaabe53afc239314c0109b52..8b6903011c323b16cc6c87af4482599fe4cb51bf 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -194,6 +194,18 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
           expect(json_response['terminal_path']).to match(%r{/terminal})
         end
       end
+
+      context 'when job passed with no trace' do
+        let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
+
+        it 'exposes empty state illustrations' do
+          expect(response).to have_gitlab_http_status(:ok)
+          expect(response).to match_response_schema('job/job_details')
+          expect(json_response['status']['illustration']).to have_key('image')
+          expect(json_response['status']['illustration']).to have_key('size')
+          expect(json_response['status']['illustration']).to have_key('title')
+        end
+      end
     end
 
     def get_show(**extra_params)
diff --git a/spec/db/importers/common_metrics_importer_spec.rb b/spec/db/importers/common_metrics_importer_spec.rb
index 16b59e1dfe876337c63ba5d6e616e33261dbd8a0..68260820958db113c904fd2bf5f319c8a18ff8c7 100644
--- a/spec/db/importers/common_metrics_importer_spec.rb
+++ b/spec/db/importers/common_metrics_importer_spec.rb
@@ -47,6 +47,16 @@ describe Importers::CommonMetricsImporter do
     end
   end
 
+  context "does import common_metrics.yml" do
+    it "when executed from outside of the Rails.root" do
+      Dir.chdir(Dir.tmpdir) do
+        expect { subject.execute }.not_to raise_error
+      end
+
+      expect(PrometheusMetric.common).not_to be_empty
+    end
+  end
+
   context 'does import properly all fields' do
     let(:query_identifier) { 'response-metric' }
     let(:group) do
diff --git a/spec/features/projects/activity/user_sees_private_activity_spec.rb b/spec/features/projects/activity/user_sees_private_activity_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d7dc0a6712a913827cc92b6b619660ee61c8f4ae
--- /dev/null
+++ b/spec/features/projects/activity/user_sees_private_activity_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe 'Project > Activity > User sees private activity', :js do
+  let(:project) { create(:project, :public) }
+  let(:author) { create(:user) }
+  let(:user) { create(:user) }
+  let(:issue) { create(:issue, :confidential, project: project, author: author) }
+  let(:message) { "#{author.name} opened issue #{issue.to_reference}" }
+
+  before do
+    project.add_developer(author)
+
+    create(:event, :created, project: project, target: issue, author: author)
+  end
+
+  it 'shows the activity to a logged-in user with permissions' do
+    sign_in(author)
+    visit activity_project_path(project)
+
+    expect(page).to have_content(message)
+  end
+
+  it 'hides the activity from a logged-in user without permissions' do
+    sign_in(user)
+    visit activity_project_path(project)
+
+    expect(page).not_to have_content(message)
+  end
+
+  it 'hides the activity from an anonymous user' do
+    visit activity_project_path(project)
+
+    expect(page).not_to have_content(message)
+  end
+end
diff --git a/spec/fixtures/api/schemas/job/job.json b/spec/fixtures/api/schemas/job/job.json
index c793d93c0f67f98e501d874dc353042f43bb0059..f5d58b21e3d198564bbb14d48413ac3623ee2ae0 100644
--- a/spec/fixtures/api/schemas/job/job.json
+++ b/spec/fixtures/api/schemas/job/job.json
@@ -25,7 +25,7 @@
     "playable": { "type": "boolean" },
     "created_at": { "type": "string" },
     "updated_at": { "type": "string" },
-    "status": { "$ref": "../ci_detailed_status.json" }
+    "status": { "$ref": "../status/ci_detailed_status.json" }
   },
   "additionalProperties": true
 }
diff --git a/spec/fixtures/api/schemas/pipeline_stage.json b/spec/fixtures/api/schemas/pipeline_stage.json
index eb2667295f0d841bb23e1aa8f6492f29be2a06e4..f72988a3d3dfabba648c481845562448cb7807b7 100644
--- a/spec/fixtures/api/schemas/pipeline_stage.json
+++ b/spec/fixtures/api/schemas/pipeline_stage.json
@@ -16,7 +16,7 @@
       "items": { "$ref": "job/job.json" },
       "optional": true
     },
-    "status": { "$ref": "ci_detailed_status.json" },
+    "status": { "$ref": "status/ci_detailed_status.json" },
     "path": { "type": "string" },
     "dropdown_path": { "type": "string" }
   },
diff --git a/spec/fixtures/api/schemas/status/action.json b/spec/fixtures/api/schemas/status/action.json
new file mode 100644
index 0000000000000000000000000000000000000000..99a576e6c5b569541f5777bc8fb72557e66c1775
--- /dev/null
+++ b/spec/fixtures/api/schemas/status/action.json
@@ -0,0 +1,22 @@
+{
+  "type": "object",
+  "required": [
+    "icon",
+    "title",
+    "path",
+    "method"
+  ],
+  "properties": {
+    "icon": {
+      "type": "string",
+      "enum": [
+        "retry",
+        "play",
+        "cancel"
+      ]
+    },
+    "title": { "type": "string" },
+    "path": { "type": "string" },
+    "method": { "$ref": "../http_method.json" }
+  }
+}
diff --git a/spec/fixtures/api/schemas/ci_detailed_status.json b/spec/fixtures/api/schemas/status/ci_detailed_status.json
similarity index 51%
rename from spec/fixtures/api/schemas/ci_detailed_status.json
rename to spec/fixtures/api/schemas/status/ci_detailed_status.json
index d74248eabef29436d16c53555b174871c66325df..8d0f1e4a6af06572a4dd02de7d09b40aee97cc14 100644
--- a/spec/fixtures/api/schemas/ci_detailed_status.json
+++ b/spec/fixtures/api/schemas/status/ci_detailed_status.json
@@ -1,6 +1,6 @@
 {
   "type": "object",
-  "required" : [
+  "required": [
     "icon",
     "text",
     "label",
@@ -19,28 +19,8 @@
     "has_details": { "type": "boolean" },
     "details_path": { "type": "string" },
     "favicon": { "type": "string" },
-    "action": {
-      "type": "object",
-      "required": [
-        "icon",
-        "title",
-        "path",
-        "method"
-      ],
-      "properties": {
-        "icon": {
-          "type": "string",
-          "enum": [
-            "retry",
-            "play",
-            "cancel"
-          ]
-        },
-        "title": { "type": "string" },
-        "path": { "type": "string" },
-        "method": { "$ref": "http_method.json" }
-      }
-    }
+    "illustration": { "$ref": "illustration.json" },
+    "action": { "$ref": "action.json" }
   },
   "additionalProperties": false
 }
diff --git a/spec/fixtures/api/schemas/status/illustration.json b/spec/fixtures/api/schemas/status/illustration.json
new file mode 100644
index 0000000000000000000000000000000000000000..9a085f5f1ee64a6afcd6f41a8c7d4497db395f46
--- /dev/null
+++ b/spec/fixtures/api/schemas/status/illustration.json
@@ -0,0 +1,19 @@
+{
+  "oneOf": [
+    { "type": "null" },
+    {
+      "type": "object",
+      "required": [
+        "image",
+        "size",
+        "title"
+      ],
+      "properties": {
+        "image": { "type": "string" },
+        "size": { "type": "string" },
+        "title": { "type": "string" },
+        "content": { "type": "string" }
+      }
+    }
+  ]
+}
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 0d9ec21b6060d9476105aa59c5cb2330c4991566..62990ddd5d8e3759f339f78017825a6de8b58d98 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -1064,11 +1064,14 @@ describe API::Users do
       expect(json_response['error']).to eq('email is missing')
     end
 
-    it "creates email" do
+    it "creates unverified email" do
       email_attrs = attributes_for :email
       expect do
         post api("/users/#{user.id}/emails", admin), email_attrs
       end.to change { user.emails.count }.by(1)
+
+      email = Email.find_by(user_id: user.id, email: email_attrs[:email])
+      expect(email).not_to be_confirmed
     end
 
     it "returns a 400 for invalid ID" do
@@ -1076,6 +1079,18 @@ describe API::Users do
 
       expect(response).to have_gitlab_http_status(400)
     end
+
+    it "creates verified email" do
+      email_attrs = attributes_for :email
+      email_attrs[:skip_confirmation] = true
+
+      post api("/users/#{user.id}/emails", admin), email_attrs
+
+      expect(response).to have_gitlab_http_status(201)
+
+      email = Email.find_by(user_id: user.id, email: email_attrs[:email])
+      expect(email).to be_confirmed
+    end
   end
 
   describe 'GET /user/:id/emails' do
diff --git a/spec/serializers/status_entity_spec.rb b/spec/serializers/detailed_status_entity_spec.rb
similarity index 95%
rename from spec/serializers/status_entity_spec.rb
rename to spec/serializers/detailed_status_entity_spec.rb
index 0b010ebd5073bff71a31b80f55ba8bbe90760179..62f57ca86899e09aa62dd33c6a2064a265916192 100644
--- a/spec/serializers/status_entity_spec.rb
+++ b/spec/serializers/detailed_status_entity_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe StatusEntity do
+describe DetailedStatusEntity do
   let(:entity) { described_class.new(status) }
 
   let(:status) do