Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml8
-rw-r--r--app/assets/javascripts/editor/editor_lite.js3
-rw-r--r--app/assets/javascripts/users_select/index.js7
-rw-r--r--app/models/diff_viewer/image.rb8
-rw-r--r--app/views/devise/shared/_tabs_ldap.html.haml8
-rw-r--r--app/workers/concerns/limited_capacity/worker.rb7
-rwxr-xr-xbin/feature-flag4
-rw-r--r--changelogs/unreleased/244831-split-pipelines-for-merged-results-and-merge-train-check-boxes.yml5
-rw-r--r--changelogs/unreleased/26952-fix-viewing-legacy-diff-notes-in-discussion.yml5
-rw-r--r--config/feature_flags/development/admin_approval_for_new_user_signups.yml7
-rw-r--r--config/initializers/0_inject_feature_flags.rb46
-rw-r--r--danger/documentation/Dangerfile4
-rw-r--r--db/migrate/20201021220101_add_merge_trains_enabled.rb9
-rw-r--r--db/migrate/20201026200736_seed_merge_trains_enabled.rb19
-rw-r--r--db/schema_migrations/202010212201011
-rw-r--r--db/schema_migrations/202010262007361
-rw-r--r--db/structure.sql3
-rw-r--r--doc/development/fe_guide/graphql.md96
-rw-r--r--doc/development/feature_flags/development.md47
-rw-r--r--doc/install/installation.md6
-rw-r--r--doc/update/upgrading_from_source.md6
-rw-r--r--lib/api/features.rb10
-rw-r--r--lib/feature/shared.rb3
-rw-r--r--spec/bin/feature_flag_spec.rb23
-rw-r--r--spec/features/users/login_spec.rb53
-rw-r--r--spec/frontend/editor/editor_lite_spec.js2
-rw-r--r--spec/migrations/seed_merge_trains_enabled_spec.rb28
-rw-r--r--spec/models/diff_viewer/image_spec.rb40
-rw-r--r--spec/support/helpers/user_login_helper.rb19
-rw-r--r--spec/workers/concerns/limited_capacity/worker_spec.rb3
32 files changed, 397 insertions, 88 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8a111b1f695..d56ff9bab7a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,7 +17,7 @@ stages:
# in cases where jobs require Docker-in-Docker, the job
# definition must be extended with `.use-docker-in-docker`
default:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.29-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
tags:
- gitlab-org
# All jobs are interruptible by default
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 1b78996282c..3d48c872d52 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -15,7 +15,7 @@
extends:
- .frontend-base
- .assets-compile-cache
- image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-git-2.28-lfs-2.9-node-12.18-yarn-1.22-graphicsmagick-1.3.34
+ image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-git-2.29-lfs-2.9-node-12.18-yarn-1.22-graphicsmagick-1.3.34
variables:
WEBPACK_VENDOR_DLL: "true"
stage: prepare
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index 3ff17ce05d2..0fafd5869d9 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -71,7 +71,7 @@
policy: pull
.use-pg11:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.29-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -80,7 +80,7 @@
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-12-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.29-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-12-graphicsmagick-1.3.34"
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -89,7 +89,7 @@
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg11-ee:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.29-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -100,7 +100,7 @@
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12-ee:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-12-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-golang-1.14-git-2.29-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-12-graphicsmagick-1.3.34"
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
diff --git a/app/assets/javascripts/editor/editor_lite.js b/app/assets/javascripts/editor/editor_lite.js
index e52e64d4c2d..e7535c211db 100644
--- a/app/assets/javascripts/editor/editor_lite.js
+++ b/app/assets/javascripts/editor/editor_lite.js
@@ -6,6 +6,7 @@ import { registerLanguages } from '~/ide/utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { clearDomElement } from './utils';
import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX } from './constants';
+import { uuids } from '~/diffs/utils/uuids';
export default class Editor {
constructor(options = {}) {
@@ -72,7 +73,7 @@ export default class Editor {
el = undefined,
blobPath = '',
blobContent = '',
- blobGlobalId = '',
+ blobGlobalId = uuids()[0],
extensions = [],
...instanceOptions
} = {}) {
diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index 20d1a3c1fcd..dccd6807f13 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -14,6 +14,7 @@ import ModalStore from '../boards/stores/modal_store';
import { parseBoolean, spriteIcon } from '../lib/utils/common_utils';
import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
+import { fixTitle, dispose } from '~/tooltips';
// TODO: remove eventHub hack after code splitting refactor
window.emitSidebarEvent = window.emitSidebarEvent || $.noop;
@@ -229,7 +230,9 @@ function UsersSelect(currentUser, els, options = {}) {
tooltipTitle = s__('UsersSelect|Assignee');
}
$value.html(assigneeTemplate(user));
- $collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle');
+ $collapsedSidebar.attr('title', tooltipTitle);
+ fixTitle($collapsedSidebar);
+
return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
});
};
@@ -423,7 +426,7 @@ function UsersSelect(currentUser, els, options = {}) {
const { $el, e, isMarking } = options;
const user = options.selectedObj;
- $el.tooltip('dispose');
+ dispose($el);
if ($dropdown.hasClass('js-multiselect')) {
const isActive = $el.hasClass('is-active');
diff --git a/app/models/diff_viewer/image.rb b/app/models/diff_viewer/image.rb
index 62a3446a7b6..fca6c664196 100644
--- a/app/models/diff_viewer/image.rb
+++ b/app/models/diff_viewer/image.rb
@@ -10,5 +10,13 @@ module DiffViewer
self.binary = true
self.switcher_icon = 'doc-image'
self.switcher_title = _('image diff')
+
+ def self.can_render?(diff_file, verify_binary: true)
+ # When both blobs are missing, we often still have a textual diff that can
+ # be displayed
+ return false if diff_file.old_blob.nil? && diff_file.new_blob.nil?
+
+ super
+ end
end
end
diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml
index acd41fb011a..27057d023b1 100644
--- a/app/views/devise/shared/_tabs_ldap.html.haml
+++ b/app/views/devise/shared/_tabs_ldap.html.haml
@@ -4,17 +4,17 @@
%ul.nav-links.new-session-tabs.nav-tabs.nav{ class: ('custom-provider-tabs' if any_form_based_providers_enabled?) }
- if crowd_enabled?
%li.nav-item
- = link_to "Crowd", "#crowd", class: "nav-link #{active_when(form_based_auth_provider_has_active_class?(:crowd))}", 'data-toggle' => 'tab'
+ = link_to "Crowd", "#crowd", class: "nav-link #{active_when(form_based_auth_provider_has_active_class?(:crowd))}", 'data-toggle' => 'tab', role: 'tab'
= render_if_exists "devise/shared/kerberos_tab"
- ldap_servers.each_with_index do |server, i|
%li.nav-item
- = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i == 0 && form_based_auth_provider_has_active_class?(:ldapmain))}", data: { toggle: 'tab', qa_selector: 'ldap_tab' }
+ = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i == 0 && form_based_auth_provider_has_active_class?(:ldapmain))}", data: { toggle: 'tab', qa_selector: 'ldap_tab' }, role: 'tab'
= render_if_exists 'devise/shared/tab_smartcard'
- if show_password_form
%li.nav-item
- = link_to _('Standard'), '#login-pane', class: 'nav-link', data: { toggle: 'tab', qa_selector: 'standard_tab' }
+ = link_to _('Standard'), '#login-pane', class: 'nav-link', data: { toggle: 'tab', qa_selector: 'standard_tab' }, role: 'tab'
- if render_signup_link && allow_signup?
%li.nav-item
- = link_to 'Register', '#register-pane', class: 'nav-link', data: { toggle: 'tab', qa_selector: 'register_tab' }
+ = link_to 'Register', '#register-pane', class: 'nav-link', data: { toggle: 'tab', qa_selector: 'register_tab' }, role: 'tab'
diff --git a/app/workers/concerns/limited_capacity/worker.rb b/app/workers/concerns/limited_capacity/worker.rb
index c0d6bfff2f5..b5a97e49300 100644
--- a/app/workers/concerns/limited_capacity/worker.rb
+++ b/app/workers/concerns/limited_capacity/worker.rb
@@ -67,6 +67,7 @@ module LimitedCapacity
return unless has_capacity?
job_tracker.register(jid)
+ report_running_jobs_metrics
perform_work(*args)
rescue => exception
raise
@@ -108,11 +109,15 @@ module LimitedCapacity
end
def report_prometheus_metrics(*args)
- running_jobs_gauge.set(prometheus_labels, running_jobs_count)
+ report_running_jobs_metrics
remaining_work_gauge.set(prometheus_labels, remaining_work_count(*args))
max_running_jobs_gauge.set(prometheus_labels, max_running_jobs)
end
+ def report_running_jobs_metrics
+ running_jobs_gauge.set(prometheus_labels, running_jobs_count)
+ end
+
def required_jobs_count(*args)
[
remaining_work_count(*args),
diff --git a/bin/feature-flag b/bin/feature-flag
index b5e7889be1d..43e273be1fa 100755
--- a/bin/feature-flag
+++ b/bin/feature-flag
@@ -126,6 +126,8 @@ class FeatureFlagOptionParser
$stdout.puts ">> Specify the feature flag type:"
$stdout.puts
TYPES.each do |type, data|
+ next if data[:deprecated]
+
$stdout.puts "#{type.to_s.rjust(15)}#{' '*6}#{data[:description]}"
end
@@ -133,7 +135,7 @@ class FeatureFlagOptionParser
$stdout.print "?> "
type = $stdin.gets.strip.to_sym
- return type if TYPES[type]
+ return type if TYPES[type] && !TYPES[type][:deprecated]
$stderr.puts "Invalid type specified '#{type}'"
end
diff --git a/changelogs/unreleased/244831-split-pipelines-for-merged-results-and-merge-train-check-boxes.yml b/changelogs/unreleased/244831-split-pipelines-for-merged-results-and-merge-train-check-boxes.yml
new file mode 100644
index 00000000000..2aac8e603aa
--- /dev/null
+++ b/changelogs/unreleased/244831-split-pipelines-for-merged-results-and-merge-train-check-boxes.yml
@@ -0,0 +1,5 @@
+---
+title: Add merge trains enabled setting to project ci cd settings
+merge_request: 45834
+author:
+type: other
diff --git a/changelogs/unreleased/26952-fix-viewing-legacy-diff-notes-in-discussion.yml b/changelogs/unreleased/26952-fix-viewing-legacy-diff-notes-in-discussion.yml
new file mode 100644
index 00000000000..f6ec87f1332
--- /dev/null
+++ b/changelogs/unreleased/26952-fix-viewing-legacy-diff-notes-in-discussion.yml
@@ -0,0 +1,5 @@
+---
+title: Fix viewing GitHub-imported diff notes in discussions
+merge_request: 45920
+author:
+type: fixed
diff --git a/config/feature_flags/development/admin_approval_for_new_user_signups.yml b/config/feature_flags/development/admin_approval_for_new_user_signups.yml
deleted file mode 100644
index 0cde210e6a0..00000000000
--- a/config/feature_flags/development/admin_approval_for_new_user_signups.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: admin_approval_for_new_user_signups
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43827
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258980
-type: development
-group: group::access
-default_enabled: true
diff --git a/config/initializers/0_inject_feature_flags.rb b/config/initializers/0_inject_feature_flags.rb
index 5b33b3bb4ea..1e0c3c01aba 100644
--- a/config/initializers/0_inject_feature_flags.rb
+++ b/config/initializers/0_inject_feature_flags.rb
@@ -4,3 +4,49 @@
Feature.register_feature_groups
Feature.register_definitions
Feature.register_hot_reloader unless Rails.configuration.cache_classes
+
+# This disallows usage of licensed feature names with the same name
+# as feature flags. This naming collision creates confusion and it was
+# decided to be removed in favor of explicit check.
+# https://gitlab.com/gitlab-org/gitlab/-/issues/259611
+if Gitlab.ee? && Gitlab.dev_or_test_env?
+ # These are the names of feature flags that do violate the constraint of
+ # being unique to licensed names. These feature flags should be reworked to
+ # be "development" with explicit check
+ IGNORED_FEATURE_FLAGS = %i[
+ resource_access_token
+ ci_secrets_management
+ feature_flags_related_issues
+ group_coverage_reports
+ group_wikis
+ incident_sla
+ swimlanes
+ minimal_access_role
+ ].to_set
+
+ # First, we validate a list of overrides to ensure that these overrides
+ # are removed if feature flag is gone
+ missing_feature_flags = IGNORED_FEATURE_FLAGS.reject do |feature_flag|
+ Feature::Definition.definitions[feature_flag]
+ end
+
+ if missing_feature_flags.any?
+ raise "The following feature flags were added as an override for discovering licensed features. " \
+ "Since these feature flags seems to be gone, ensure to remove them from \`IGNORED_FEATURE_FLAGS\` " \
+ "in \`#{__FILE__}'`: #{missing_feature_flags.join(", ")}"
+ end
+
+ # Second, we validate that there's no feature flag under the name as licensed feature
+ # flag, to ensure that the name used, is unique
+ licensed_features = License::PLANS_BY_FEATURE.keys.select do |licensed_feature_name|
+ IGNORED_FEATURE_FLAGS.exclude?(licensed_feature_name) &&
+ Feature::Definition.definitions[licensed_feature_name]
+ end
+
+ if licensed_features.any?
+ raise "The following feature flags do use a licensed feature. " \
+ "To avoid the confusion between their usage it is disallowed to use feature flag " \
+ "with exact the same name as licensed feature name. Use a different name to create " \
+ "a distinction: #{licensed_features.join(", ")}"
+ end
+end
diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile
index 37fad668521..240c374435c 100644
--- a/danger/documentation/Dangerfile
+++ b/danger/documentation/Dangerfile
@@ -5,7 +5,9 @@ def gitlab_danger
end
def feature_mr?
- (gitlab.mr_labels & %w[feature::addition feature::enhancement]).any?
+ return false unless helper.gitlab_helper&.mr_labels
+
+ (helper.gitlab_helper.mr_labels & %w[feature::addition feature::enhancement]).any?
end
DOCUMENTATION_UPDATE_MISSING = <<~MSG
diff --git a/db/migrate/20201021220101_add_merge_trains_enabled.rb b/db/migrate/20201021220101_add_merge_trains_enabled.rb
new file mode 100644
index 00000000000..88a71897435
--- /dev/null
+++ b/db/migrate/20201021220101_add_merge_trains_enabled.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddMergeTrainsEnabled < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: false
+ end
+end
diff --git a/db/migrate/20201026200736_seed_merge_trains_enabled.rb b/db/migrate/20201026200736_seed_merge_trains_enabled.rb
new file mode 100644
index 00000000000..c22c2a408bc
--- /dev/null
+++ b/db/migrate/20201026200736_seed_merge_trains_enabled.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class SeedMergeTrainsEnabled < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ update_column_in_batches(:project_ci_cd_settings, :merge_trains_enabled, true) do |table, query|
+ query.where(table[:merge_pipelines_enabled].eq(true))
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20201021220101 b/db/schema_migrations/20201021220101
new file mode 100644
index 00000000000..cda2e4076a5
--- /dev/null
+++ b/db/schema_migrations/20201021220101
@@ -0,0 +1 @@
+72580665fcb0fca332ede450690902c0a7afb6159feff41df1bc10a3cf6607f2 \ No newline at end of file
diff --git a/db/schema_migrations/20201026200736 b/db/schema_migrations/20201026200736
new file mode 100644
index 00000000000..7ed57505c3e
--- /dev/null
+++ b/db/schema_migrations/20201026200736
@@ -0,0 +1 @@
+691fe3335de3e072bc5612705c4d16744ff17e334025ddd78eb37309f87441e3 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c08fc55fef0..c117864ff81 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -14822,7 +14822,8 @@ CREATE TABLE project_ci_cd_settings (
group_runners_enabled boolean DEFAULT true NOT NULL,
merge_pipelines_enabled boolean,
default_git_depth integer,
- forward_deployment_enabled boolean
+ forward_deployment_enabled boolean,
+ merge_trains_enabled boolean DEFAULT false
);
CREATE SEQUENCE project_ci_cd_settings_id_seq
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index ad3958d4496..a6e5a1b9b12 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -910,3 +910,99 @@ const defaultClient = createDefaultClient(
},
);
```
+
+## Making initial queries early with GraphQL startup calls
+
+To improve performance, sometimes we want to make initial GraphQL queries early. In order to do this, we can add them to **startup calls** with the following steps:
+
+- Move all the queries you need initially in your application to `app/graphql/queries`;
+- Add `__typename` property to every nested query level:
+
+ ```javascript
+ query getPermissions($projectPath: ID!) {
+ project(fullPath: $projectPath) {
+ __typename
+ userPermissions {
+ __typename
+ pushCode
+ forkProject
+ createMergeRequestIn
+ }
+ }
+ }
+ ```
+
+- If queries contain fragments, you need to move fragments to the query file directly instead of importing them:
+
+ ```javascript
+ fragment PageInfo on PageInfo {
+ __typename
+ hasNextPage
+ hasPreviousPage
+ startCursor
+ endCursor
+ }
+
+ query getFiles(
+ $projectPath: ID!
+ $path: String
+ $ref: String!
+ ) {
+ project(fullPath: $projectPath) {
+ __typename
+ repository {
+ __typename
+ tree(path: $path, ref: $ref) {
+ __typename
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ }
+ }
+ }
+ }
+ ```
+
+- If the fragment is used only once, we can also remove the fragment altogether:
+
+ ```javascript
+ query getFiles(
+ $projectPath: ID!
+ $path: String
+ $ref: String!
+ ) {
+ project(fullPath: $projectPath) {
+ __typename
+ repository {
+ __typename
+ tree(path: $path, ref: $ref) {
+ __typename
+ pageInfo {
+ __typename
+ hasNextPage
+ hasPreviousPage
+ startCursor
+ endCursor
+ }
+ }
+ }
+ }
+ }
+ }
+ ```
+
+- Add startup call(s) with correct variables to the HAML file that serves as a view
+for your application. To add GraphQL startup calls, we use
+`add_page_startup_graphql_call` helper where the first parameter is a path to the
+query, the second one is an object containing query variables. Path to the query is
+relative to `app/graphql/queries` folder: for example, if we need a
+`app/graphql/queries/repository/files.query.graphql` query, the path will be
+`repository/files`.
+
+ ```yaml
+ - current_route_path = request.fullpath.match(/-\/tree\/[^\/]+\/(.+$)/).to_a[1]
+ - add_page_startup_graphql_call('repository/path_last_commit', { projectPath: @project.full_path, ref: current_ref, path: current_route_path || "" })
+ - add_page_startup_graphql_call('repository/permissions', { projectPath: @project.full_path })
+ - add_page_startup_graphql_call('repository/files', { nextPageCursor: "", pageSize: 100, projectPath: @project.full_path, ref: current_ref, path: current_route_path || "/"})
+ ```
diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md
index e6668b0fd03..6c672663bae 100644
--- a/doc/development/feature_flags/development.md
+++ b/doc/development/feature_flags/development.md
@@ -61,30 +61,6 @@ Feature.disabled?(:my_ops_flag, project, type: :ops)
push_frontend_feature_flag(:my_ops_flag, project, type: :ops)
```
-### `licensed` type
-
-`licensed` feature flags are used to temporarily disable licensed features. There
-should be a one-to-one mapping of `licensed` feature flags to licensed features.
-
-`licensed` feature flags must be `default_enabled: true`, because that's the only
-supported option in the current implementation. This is under development as per
-the [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/218667).
-
-The `licensed` type has a dedicated set of functions to check if a licensed
-feature is available for a project or namespace. This check validates
-if the license is assigned to the namespace and feature flag itself.
-The `licensed` feature flag has the same name as a licensed feature name:
-
-```ruby
-# Good: checks if feature flag is enabled
-project.feature_available?(:my_licensed_feature)
-namespace.feature_available?(:my_licensed_feature)
-
-# Bad: licensed flag must be accessed via `feature_available?`
-Feature.enabled?(:my_licensed_feature, type: :licensed)
-push_frontend_feature_flag(:my_licensed_feature, type: :licensed)
-```
-
## Feature flag definition and validation
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229161) in GitLab 13.3.
@@ -309,25 +285,16 @@ used as an actor for `Feature.enabled?`.
### Feature flags for licensed features
-The [`Project#feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/app/models/project_feature.rb#L63-68),
-[`Namespace#feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/ee/namespace.rb#L71-85) (EE), and
-[`License.feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300) (EE) methods all implicitly check for
-a by default enabled feature flag with the same name as the provided argument.
-
-**An important side-effect of the implicit feature flags mentioned above is that
-unless the feature is explicitly disabled or limited to a percentage of users,
-the feature flag check defaults to `true`.**
-
-NOTE: **Note:**
-Due to limitations with `feature_available?`, the YAML definition for `licensed` feature
-flags accepts only `default_enabled: true`. This is under development as per the
-[related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/218667).
+You can't use a feature flag with the same name as a licensed feature name, because
+it would cause a naming collision. This was [widely discussed and removed](https://gitlab.com/gitlab-org/gitlab/-/issues/259611)
+because it is confusing.
-If you want a licensed feature to be disabled by default or enabled only for a given gate, you can use a feature flag with a different name. The feature checks would then
-look like:
+To check for licensed features, add a dedicated feature flag under a different name
+and check it explicitly, for example:
```ruby
-Feature.enabled?(:licensed_feature_feature_flag, project) && project.feature_available?(:licensed_feature)
+Feature.enabled?(:licensed_feature_feature_flag, project) &&
+ project.feature_available?(:licensed_feature)
```
### Feature groups
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 597357f1349..4b93d02815f 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -181,9 +181,9 @@ sudo make install
# Download and compile from source
cd /tmp
-curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz
-echo 'f914c60a874d466c1e18467c864a910dd4ea22281ba6d4d58077cb0c3f115170 git-2.28.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.28.0.tar.gz
-cd git-2.28.0/
+curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.29.0.tar.gz
+echo 'fa08dc8424ef80c0f9bf307877f9e2e49f1a6049e873530d6747c2be770742ff git-2.29.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.29.0.tar.gz
+cd git-2.29.0/
./configure --with-libpcre
make prefix=/usr/local all
diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md
index a0f042acab2..e570042e607 100644
--- a/doc/update/upgrading_from_source.md
+++ b/doc/update/upgrading_from_source.md
@@ -152,9 +152,9 @@ make install
# Download and compile from source
cd /tmp
-curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz
-echo 'f914c60a874d466c1e18467c864a910dd4ea22281ba6d4d58077cb0c3f115170 git-2.28.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.28.0.tar.gz
-cd git-2.28.0/
+curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.29.0.tar.gz
+echo 'fa08dc8424ef80c0f9bf307877f9e2e49f1a6049e873530d6747c2be770742ff git-2.29.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.29.0.tar.gz
+cd git-2.29.0/
./configure --with-libpcre
make prefix=/usr/local all
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 5d2e545abd6..70feef12ceb 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -61,6 +61,8 @@ module API
mutually_exclusive :key, :project
end
post ':name' do
+ validate_feature_flag_name!(params[:name])
+
feature = Feature.get(params[:name]) # rubocop:disable Gitlab/AvoidFeatureGet
targets = gate_targets(params)
value = gate_value(params)
@@ -97,5 +99,13 @@ module API
no_content!
end
end
+
+ helpers do
+ def validate_feature_flag_name!(name)
+ # no-op
+ end
+ end
end
end
+
+API::Features.prepend_if_ee('EE::API::Features')
diff --git a/lib/feature/shared.rb b/lib/feature/shared.rb
index 9ec56ee6b52..5716bc007a6 100644
--- a/lib/feature/shared.rb
+++ b/lib/feature/shared.rb
@@ -10,6 +10,8 @@ class Feature
# rollout_issue: defines if `bin/feature-flag` asks for rollout issue
# default_enabled: defines a default state of a feature flag when created by `bin/feature-flag`
# ee_only: defines that a feature flag can only be created in a context of EE
+ # deprecated: defines if a feature flag type that is deprecated and to be removed,
+ # the deprecated types are hidden from all interfaces
# example: usage being shown when exception is raised
TYPES = {
development: {
@@ -37,6 +39,7 @@ class Feature
},
licensed: {
description: 'Permanent feature flags used to temporarily disable licensed features.',
+ deprecated: true,
optional: true,
rollout_issue: false,
ee_only: true,
diff --git a/spec/bin/feature_flag_spec.rb b/spec/bin/feature_flag_spec.rb
index 185a03fc587..8e0bed5b769 100644
--- a/spec/bin/feature_flag_spec.rb
+++ b/spec/bin/feature_flag_spec.rb
@@ -123,6 +123,29 @@ RSpec.describe 'bin/feature-flag' do
end
end
+ context 'when there is deprecated feature flag type' do
+ before do
+ stub_const('FeatureFlagOptionParser::TYPES',
+ development: { description: 'short' },
+ deprecated: { description: 'deprecated', deprecated: true }
+ )
+ end
+
+ context 'and deprecated type is given' do
+ let(:type) { 'deprecated' }
+
+ it 'shows error message and retries' do
+ expect($stdin).to receive(:gets).and_return(type)
+ expect($stdin).to receive(:gets).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_type }.to raise_error(/EOF/)
+ end.to output(/Specify the feature flag type/).to_stdout
+ .and output(/Invalid type specified/).to_stderr
+ end
+ end
+ end
+
context 'when there are many types defined' do
before do
stub_const('FeatureFlagOptionParser::TYPES',
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 853c381fe6b..f56c6f28f9d 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -594,41 +594,78 @@ RSpec.describe 'Login' do
describe 'UI tabs and panes' do
context 'when no defaults are changed' do
it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness
+ visit new_user_session_path
+
+ ensure_tab_pane_correctness(['Sign in', 'Register'])
end
end
context 'when signup is disabled' do
before do
stub_application_setting(signup_enabled: false)
+
+ visit new_user_session_path
end
it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness
+ ensure_tab_pane_correctness(['Sign in'])
end
end
context 'when ldap is enabled' do
+ include LdapHelpers
+
+ let(:provider) { 'ldapmain' }
+ let(:ldap_server_config) do
+ {
+ 'label' => 'Main LDAP',
+ 'provider_name' => provider,
+ 'attributes' => {},
+ 'encryption' => 'plain',
+ 'uid' => 'uid',
+ 'base' => 'dc=example,dc=com'
+ }
+ end
+
before do
+ stub_ldap_setting(enabled: true)
+ allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config])
+ allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym])
+
+ Ldap::OmniauthCallbacksController.define_providers!
+ Rails.application.reload_routes!
+
+ allow_next_instance_of(ActionDispatch::Routing::RoutesProxy) do |instance|
+ allow(instance).to receive(:"user_#{provider}_omniauth_callback_path")
+ .and_return("/users/auth/#{provider}/callback")
+ end
+
visit new_user_session_path
- allow(page).to receive(:form_based_providers).and_return([:ldapmain])
- allow(page).to receive(:ldap_enabled).and_return(true)
end
it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness(false)
+ ensure_tab_pane_correctness(['Main LDAP', 'Standard', 'Register'])
end
end
context 'when crowd is enabled' do
before do
+ allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [:crowd])
+ stub_application_setting(crowd_enabled: true)
+
+ Ldap::OmniauthCallbacksController.define_providers!
+ Rails.application.reload_routes!
+
+ allow_next_instance_of(ActionDispatch::Routing::RoutesProxy) do |instance|
+ allow(instance).to receive(:user_crowd_omniauth_authorize_path)
+ .and_return("/users/auth/crowd/callback")
+ end
+
visit new_user_session_path
- allow(page).to receive(:form_based_providers).and_return([:crowd])
- allow(page).to receive(:crowd_enabled?).and_return(true)
end
it 'correctly renders tabs and panes' do
- ensure_tab_pane_correctness(false)
+ ensure_tab_pane_correctness(%w(Crowd Standard Register))
end
end
end
diff --git a/spec/frontend/editor/editor_lite_spec.js b/spec/frontend/editor/editor_lite_spec.js
index bc17435c6d4..2968984df01 100644
--- a/spec/frontend/editor/editor_lite_spec.js
+++ b/spec/frontend/editor/editor_lite_spec.js
@@ -64,7 +64,7 @@ describe('Base editor', () => {
});
it('creates model to be supplied to Monaco editor', () => {
- editor.createInstance({ el: editorEl, blobPath, blobContent });
+ editor.createInstance({ el: editorEl, blobPath, blobContent, blobGlobalId: '' });
expect(modelSpy).toHaveBeenCalledWith(blobContent, undefined, createUri(blobPath));
expect(setModel).toHaveBeenCalledWith(fakeModel);
diff --git a/spec/migrations/seed_merge_trains_enabled_spec.rb b/spec/migrations/seed_merge_trains_enabled_spec.rb
new file mode 100644
index 00000000000..2abb064a111
--- /dev/null
+++ b/spec/migrations/seed_merge_trains_enabled_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20201026200736_seed_merge_trains_enabled.rb')
+
+RSpec.describe SeedMergeTrainsEnabled do
+ describe 'migrate' do
+ let(:project_ci_cd_settings) { table(:project_ci_cd_settings) }
+ let(:projects) { table(:projects) }
+ let(:namespaces) { table(:namespaces) }
+
+ context 'when on Gitlab.com' do
+ before do
+ namespace = namespaces.create!(name: 'hello', path: 'hello/')
+ project1 = projects.create!(namespace_id: namespace.id)
+ project2 = projects.create!(namespace_id: namespace.id)
+ project_ci_cd_settings.create!(project_id: project1.id, merge_pipelines_enabled: true)
+ project_ci_cd_settings.create!(project_id: project2.id, merge_pipelines_enabled: false)
+ end
+
+ it 'updates merge_trains_enabled to true for where merge_pipelines_enabled is true' do
+ migrate!
+
+ expect(project_ci_cd_settings.where(merge_trains_enabled: true).count).to be(1)
+ end
+ end
+ end
+end
diff --git a/spec/models/diff_viewer/image_spec.rb b/spec/models/diff_viewer/image_spec.rb
new file mode 100644
index 00000000000..e959a7d5eb2
--- /dev/null
+++ b/spec/models/diff_viewer/image_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DiffViewer::Image do
+ describe '.can_render?' do
+ let(:diff_file) { double(Gitlab::Diff::File) }
+ let(:blob) { double(Gitlab::Git::Blob, binary_in_repo?: true, extension: 'png') }
+
+ subject { described_class.can_render?(diff_file, verify_binary: false) }
+
+ it 'returns false if both old and new blob are absent' do
+ allow(diff_file).to receive(:old_blob) { nil }
+ allow(diff_file).to receive(:new_blob) { nil }
+
+ is_expected.to be_falsy
+ end
+
+ it 'returns true if the old blob is present' do
+ allow(diff_file).to receive(:old_blob) { blob }
+ allow(diff_file).to receive(:new_blob) { nil }
+
+ is_expected.to be_truthy
+ end
+
+ it 'returns true if the new blob is present' do
+ allow(diff_file).to receive(:old_blob) { nil }
+ allow(diff_file).to receive(:new_blob) { blob }
+
+ is_expected.to be_truthy
+ end
+
+ it 'returns true if both old and new blobs are present' do
+ allow(diff_file).to receive(:old_blob) { blob }
+ allow(diff_file).to receive(:new_blob) { blob }
+
+ is_expected.to be_truthy
+ end
+ end
+end
diff --git a/spec/support/helpers/user_login_helper.rb b/spec/support/helpers/user_login_helper.rb
index 66606832883..925576119bb 100644
--- a/spec/support/helpers/user_login_helper.rb
+++ b/spec/support/helpers/user_login_helper.rb
@@ -1,18 +1,21 @@
# frozen_string_literal: true
module UserLoginHelper
- def ensure_tab_pane_correctness(visit_path = true)
- if visit_path
- visit new_user_session_path
- end
-
- ensure_tab_pane_counts
+ def ensure_tab_pane_correctness(tab_names)
+ ensure_tab_pane_counts(tab_names.size)
+ ensure_tab_labels(tab_names)
ensure_one_active_tab
ensure_one_active_pane
end
- def ensure_tab_pane_counts
- tabs_count = page.all('[role="tab"]').size
+ def ensure_tab_labels(tab_names)
+ tab_labels = page.all('[role="tab"]').map(&:text)
+
+ expect(tab_names).to match_array(tab_labels)
+ end
+
+ def ensure_tab_pane_counts(tabs_count)
+ expect(page.all('[role="tab"]').size).to eq(tabs_count)
expect(page).to have_selector('[role="tabpanel"]', visible: :all, count: tabs_count)
end
diff --git a/spec/workers/concerns/limited_capacity/worker_spec.rb b/spec/workers/concerns/limited_capacity/worker_spec.rb
index 8a15675c04d..2c33c8666ec 100644
--- a/spec/workers/concerns/limited_capacity/worker_spec.rb
+++ b/spec/workers/concerns/limited_capacity/worker_spec.rb
@@ -121,7 +121,8 @@ RSpec.describe LimitedCapacity::Worker, :clean_gitlab_redis_queues, :aggregate_f
it 'reports prometheus metrics' do
allow(worker).to receive(:perform_work)
- expect(worker).to receive(:report_prometheus_metrics)
+ expect(worker).to receive(:report_prometheus_metrics).once.and_call_original
+ expect(worker).to receive(:report_running_jobs_metrics).twice.and_call_original
perform
end