Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
abd24a801e
commit
1c27dcaf69
54 changed files with 259 additions and 138 deletions
|
@ -3,7 +3,7 @@ export const loadViewer = (type) => {
|
|||
case 'empty':
|
||||
return () => import(/* webpackChunkName: 'blob_empty_viewer' */ './empty_viewer.vue');
|
||||
case 'text':
|
||||
return gon.features.refactorTextViewer
|
||||
return gon.features.highlightJs
|
||||
? () => import(/* webpackChunkName: 'blob_text_viewer' */ './text_viewer.vue')
|
||||
: null;
|
||||
case 'download':
|
||||
|
|
|
@ -92,7 +92,6 @@ class GroupsController < Groups::ApplicationController
|
|||
if @group.import_state&.in_progress?
|
||||
redirect_to group_import_path(@group)
|
||||
else
|
||||
publish_invite_members_for_task_experiment
|
||||
render_show_html
|
||||
end
|
||||
end
|
||||
|
@ -380,13 +379,6 @@ class GroupsController < Groups::ApplicationController
|
|||
def captcha_required?
|
||||
captcha_enabled? && !params[:parent_id]
|
||||
end
|
||||
|
||||
def publish_invite_members_for_task_experiment
|
||||
return unless params[:open_modal] == 'invite_members_for_task'
|
||||
return unless current_user&.can?(:admin_group_member, @group)
|
||||
|
||||
experiment(:invite_members_for_task, namespace: @group).publish_to_client
|
||||
end
|
||||
end
|
||||
|
||||
GroupsController.prepend_mod_with('GroupsController')
|
||||
|
|
|
@ -44,7 +44,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:refactor_text_viewer, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
|
||||
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
before_action do
|
||||
push_frontend_feature_flag(:lazy_load_commits, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:refactor_text_viewer, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml)
|
||||
end
|
||||
|
|
|
@ -72,8 +72,6 @@ module Registrations
|
|||
end
|
||||
|
||||
def show_tasks_to_be_done?
|
||||
return unless experiment(:invite_members_for_task).enabled?
|
||||
|
||||
MemberTask.for_members(current_user.members).exists?
|
||||
end
|
||||
|
||||
|
|
|
@ -83,9 +83,8 @@ module InviteMembersHelper
|
|||
def show_invite_members_for_task?(source)
|
||||
return unless current_user
|
||||
|
||||
invite_members_for_task_experiment = experiment(:invite_members_for_task).enabled? && params[:open_modal] == 'invite_members_for_task'
|
||||
invite_for_help_continuous_onboarding = source.is_a?(Project) && experiment(:invite_for_help_continuous_onboarding, namespace: source.namespace).variant.name == 'candidate'
|
||||
invite_members_for_task_experiment || invite_for_help_continuous_onboarding
|
||||
params[:open_modal] == 'invite_members_for_task' || invite_for_help_continuous_onboarding
|
||||
end
|
||||
|
||||
def tasks_to_be_done_options
|
||||
|
|
|
@ -405,6 +405,16 @@ module ProjectsHelper
|
|||
project.path_with_namespace
|
||||
end
|
||||
|
||||
def fork_button_disabled_tooltip(project)
|
||||
return unless current_user
|
||||
|
||||
if !current_user.can?(:fork_project, project)
|
||||
s_("ProjectOverview|You don't have permission to fork this project")
|
||||
elsif !current_user.can?(:create_fork)
|
||||
s_('ProjectOverview|You have reached your project limit')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tab_ability_map
|
||||
|
|
|
@ -417,11 +417,9 @@ class Member < ApplicationRecord
|
|||
def after_accept_invite
|
||||
post_create_hook
|
||||
|
||||
if experiment(:invite_members_for_task).enabled?
|
||||
run_after_commit_or_now do
|
||||
if member_task
|
||||
TasksToBeDone::CreateWorker.perform_async(member_task.id, created_by_id, [user_id.to_i])
|
||||
end
|
||||
run_after_commit_or_now do
|
||||
if member_task
|
||||
TasksToBeDone::CreateWorker.perform_async(member_task.id, created_by_id, [user_id.to_i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -51,9 +51,7 @@ class Namespace < ApplicationRecord
|
|||
|
||||
# This should _not_ be `inverse_of: :namespace`, because that would also set
|
||||
# `user.namespace` when this user creates a group with themselves as `owner`.
|
||||
# TODO: can this be moved into the UserNamespace class?
|
||||
# evaluate in issue https://gitlab.com/gitlab-org/gitlab/-/issues/341070
|
||||
belongs_to :owner, class_name: "User"
|
||||
belongs_to :owner, class_name: 'User'
|
||||
|
||||
belongs_to :parent, class_name: "Namespace"
|
||||
has_many :children, -> { where(type: Group.sti_name) }, class_name: "Namespace", foreign_key: :parent_id
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# TODO: currently not created/mapped in the database, will be done in another issue
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/341070
|
||||
module Namespaces
|
||||
####################################################################
|
||||
# PLEASE DO NOT OVERRIDE METHODS IN THIS CLASS!
|
||||
|
|
|
@ -117,7 +117,6 @@ module Members
|
|||
end
|
||||
|
||||
def create_tasks_to_be_done
|
||||
return unless experiment(:invite_members_for_task).enabled?
|
||||
return if params[:tasks_to_be_done].blank? || params[:tasks_project_id].blank?
|
||||
|
||||
valid_members = members.select { |member| member.valid? && member.member_task.valid? }
|
||||
|
|
|
@ -65,7 +65,6 @@ module Members
|
|||
end
|
||||
|
||||
def create_member_task
|
||||
return unless experiment(:invite_members_for_task).enabled?
|
||||
return unless member.persisted?
|
||||
return if member_task_attributes.value?(nil)
|
||||
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
- unless @project.empty_repo?
|
||||
- if current_user && can?(current_user, :fork_project, @project)
|
||||
- if current_user
|
||||
.count-badge.btn-group
|
||||
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
|
||||
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'gl-button btn btn-default btn-sm has-tooltip fork-btn' do
|
||||
= sprite_icon('fork', css_class: 'icon')
|
||||
%span= s_('ProjectOverview|Fork')
|
||||
- else
|
||||
- can_create_fork = current_user.can?(:create_fork)
|
||||
- disabled_fork_tooltip = s_('ProjectOverview|You have reached your project limit')
|
||||
%span.btn-group.has-tooltip{ title: (disabled_fork_tooltip unless can_create_fork) }
|
||||
= link_to new_project_fork_path(@project), class: "gl-button btn btn-default btn-sm fork-btn #{' disabled' unless can_create_fork }", 'aria-label' => (disabled_fork_tooltip unless can_create_fork) do
|
||||
- disabled_tooltip = fork_button_disabled_tooltip(@project)
|
||||
- count_class = 'disabled' unless can?(current_user, :download_code, @project)
|
||||
- button_class = 'disabled' if disabled_tooltip
|
||||
|
||||
%span.btn-group{ class: ('has-tooltip' if disabled_tooltip), title: disabled_tooltip }
|
||||
= link_to new_project_fork_path(@project), class: "gl-button btn btn-default btn-sm fork-btn #{button_class}" do
|
||||
= sprite_icon('fork', css_class: 'icon')
|
||||
%span= s_('ProjectOverview|Fork')
|
||||
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Forks'), s_('ProjectOverview|Forks'), @project.forks_count), class: 'gl-button btn btn-default btn-sm count has-tooltip' do
|
||||
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Forks'), s_('ProjectOverview|Forks'), @project.forks_count), class: "gl-button btn btn-default btn-sm count has-tooltip #{count_class}" do
|
||||
= @project.forks_count
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: invite_members_for_task
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339747
|
||||
milestone: '14.5'
|
||||
type: experiment
|
||||
group: group::activation
|
||||
name: highlight_js
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75005
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/346257
|
||||
milestone: '14.6'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: refactor_text_viewer
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70909
|
||||
rollout_issue_url:
|
||||
milestone: '14.4'
|
||||
type: development
|
||||
group: 'group::source code'
|
||||
default_enabled: false
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ChangeDefaultValueOfLooseFkDeletedRecordsPartition < Gitlab::Database::Migration[1.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
change_column_default(:loose_foreign_keys_deleted_records, :partition, from: nil, to: 1)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveHardcodedPartitionFromLooseFkTriggerFunction < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
|
||||
|
||||
enable_lock_retries!
|
||||
|
||||
def up
|
||||
execute(<<~SQL)
|
||||
CREATE OR REPLACE FUNCTION #{DELETED_RECORDS_INSERT_FUNCTION_NAME}()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
INSERT INTO loose_foreign_keys_deleted_records
|
||||
(fully_qualified_table_name, primary_key_value)
|
||||
SELECT TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, old_table.id FROM old_table;
|
||||
|
||||
RETURN NULL;
|
||||
END
|
||||
$$ LANGUAGE PLPGSQL
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute(<<~SQL)
|
||||
CREATE OR REPLACE FUNCTION #{DELETED_RECORDS_INSERT_FUNCTION_NAME}()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
INSERT INTO loose_foreign_keys_deleted_records
|
||||
(partition, fully_qualified_table_name, primary_key_value)
|
||||
SELECT 1, TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, old_table.id FROM old_table
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
RETURN NULL;
|
||||
END
|
||||
$$ LANGUAGE PLPGSQL
|
||||
SQL
|
||||
end
|
||||
end
|
1
db/schema_migrations/20211118100959
Normal file
1
db/schema_migrations/20211118100959
Normal file
|
@ -0,0 +1 @@
|
|||
8b1bb9758150151518f16307d3f145431000b7edf946fd44e54cf7301087b002
|
1
db/schema_migrations/20211118103439
Normal file
1
db/schema_migrations/20211118103439
Normal file
|
@ -0,0 +1 @@
|
|||
721f1ada9fe5a3d7e5da3750a43d5021a85a26e8adc4d649e7f0fff8cdf68344
|
|
@ -27,9 +27,8 @@ CREATE FUNCTION insert_into_loose_foreign_keys_deleted_records() RETURNS trigger
|
|||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO loose_foreign_keys_deleted_records
|
||||
(partition, fully_qualified_table_name, primary_key_value)
|
||||
SELECT 1, TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, old_table.id FROM old_table
|
||||
ON CONFLICT DO NOTHING;
|
||||
(fully_qualified_table_name, primary_key_value)
|
||||
SELECT TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, old_table.id FROM old_table;
|
||||
|
||||
RETURN NULL;
|
||||
END
|
||||
|
@ -1016,7 +1015,7 @@ ALTER TABLE ONLY analytics_cycle_analytics_merge_request_stage_events ATTACH PAR
|
|||
|
||||
CREATE TABLE loose_foreign_keys_deleted_records (
|
||||
id bigint NOT NULL,
|
||||
partition bigint NOT NULL,
|
||||
partition bigint DEFAULT 1 NOT NULL,
|
||||
primary_key_value bigint NOT NULL,
|
||||
status smallint DEFAULT 1 NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
|
@ -1037,7 +1036,7 @@ ALTER SEQUENCE loose_foreign_keys_deleted_records_id_seq OWNED BY loose_foreign_
|
|||
|
||||
CREATE TABLE gitlab_partitions_static.loose_foreign_keys_deleted_records_1 (
|
||||
id bigint DEFAULT nextval('loose_foreign_keys_deleted_records_id_seq'::regclass) NOT NULL,
|
||||
partition bigint NOT NULL,
|
||||
partition bigint DEFAULT 1 NOT NULL,
|
||||
primary_key_value bigint NOT NULL,
|
||||
status smallint DEFAULT 1 NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
|
|
|
@ -595,7 +595,7 @@ User.active.count
|
|||
User.billable.count
|
||||
|
||||
# The historical max on the instance as of the past year
|
||||
::HistoricalData.max_historical_user_count
|
||||
::HistoricalData.max_historical_user_count(from: 1.year.ago.beginning_of_day, to: Time.current.end_of_day)
|
||||
```
|
||||
|
||||
Using cURL and jq (up to a max 100, see the [pagination docs](../../api/index.md#pagination)):
|
||||
|
|
|
@ -43,8 +43,8 @@ POST /projects/:id/invitations
|
|||
| `expires_at` | string | no | A date string in the format YEAR-MONTH-DAY |
|
||||
| `invite_source` | string | no | The source of the invitation that starts the member creation process. See [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/327120). |
|
||||
| `areas_of_focus` | string | no | Areas the inviter wants the member to focus upon. |
|
||||
| `tasks_to_be_done` | array of strings | no | Tasks the inviter wants the member to focus on. The tasks are added as issues to a specified project. The possible values are: `ci`, `code` and `issues`. If specified, requires `tasks_project_id`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299) in GitLab 14.5 [with a flag](../administration/feature_flags.md) named `invite_members_for_task`. Disabled by default. |
|
||||
| `tasks_project_id` | integer | no | The project ID in which to create the task issues. If specified, requires `tasks_to_be_done`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299) in GitLab 14.5 [with a flag](../administration/feature_flags.md) named `invite_members_for_task`. Disabled by default. |
|
||||
| `tasks_to_be_done` | array of strings | no | Tasks the inviter wants the member to focus on. The tasks are added as issues to a specified project. The possible values are: `ci`, `code` and `issues`. If specified, requires `tasks_project_id`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299) in GitLab 14.6 |
|
||||
| `tasks_project_id` | integer | no | The project ID in which to create the task issues. If specified, requires `tasks_to_be_done`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299) in GitLab 14.6 |
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
|
|
|
@ -148,6 +148,13 @@ If you must refer to the checkbox, you can say it is selected or cleared. For ex
|
|||
- Ensure the **Protect environment** checkbox is cleared.
|
||||
- Ensure the **Protect environment** checkbox is selected.
|
||||
|
||||
## checkout, check out
|
||||
|
||||
Use **check out** as a verb. For the Git command, use `checkout`.
|
||||
|
||||
- Use `git checkout` to check out a branch locally.
|
||||
- Check out the files you want to edit.
|
||||
|
||||
## CI/CD
|
||||
|
||||
CI/CD is always uppercase. No need to spell it out on first use.
|
||||
|
@ -478,6 +485,19 @@ The word **once** means **one time**. Don't use it to mean **after** or **when**
|
|||
- Do: When the process is complete...
|
||||
- Do not: Once the process is complete...
|
||||
|
||||
## only
|
||||
|
||||
Put the word **only** next to the word it modifies.
|
||||
|
||||
- You can create only private projects.
|
||||
|
||||
In this example, **only** modifies the noun **projects**. The sentence means you can create one type of project--a private project.
|
||||
|
||||
- You can only create private projects.
|
||||
|
||||
In this example, **only** modifies the verb **create**. This sentence means that you can't perform other actions,
|
||||
like deleting private projects, or adding users to them.
|
||||
|
||||
## Owner
|
||||
|
||||
When writing about the Owner role:
|
||||
|
|
|
@ -133,11 +133,9 @@ You can mark that content for translation with:
|
|||
|
||||
The `~/locale` module exports the following key functions for externalization:
|
||||
|
||||
- `__()` (double underscore parenthesis)
|
||||
- `s__()` (namespaced double underscore parenthesis)
|
||||
- `__()` Mark content for translation (note the double underscore).
|
||||
- `s__()` Mark namespaced content for translation
|
||||
- `n__()` Mark pluralized content for translation
|
||||
- `__()` Mark content for translation (double underscore parenthesis).
|
||||
- `s__()` Mark namespaced content for translation (s double underscore parenthesis).
|
||||
- `n__()` Mark pluralized content for translation (n double underscore parenthesis).
|
||||
|
||||
```javascript
|
||||
import { __, s__, n__ } from '~/locale';
|
||||
|
|
|
@ -135,6 +135,27 @@ with the following differences:
|
|||
|
||||
## Remove the GitLab Kubernetes Agent
|
||||
|
||||
1. Get the `<cluster-agent-id>` and the `<cluster-agent-token-id>` from a query in the interactive GraphQL explorer.
|
||||
For GitLab.com, go to <https://gitlab.com/-/graphql-explorer> to open GraphQL Explorer.
|
||||
For self-managed GitLab instances, go to `https://gitlab.example.com/-/graphql-explorer`, replacing `gitlab.example.com` with your own instance's URL.
|
||||
|
||||
```graphql
|
||||
query{
|
||||
project(fullPath: "<full-path-to-agent-configuration-project>") {
|
||||
clusterAgent(name: "<agent-name>") {
|
||||
id
|
||||
tokens {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Remove an Agent record with GraphQL by deleting the `clusterAgent` and the `clusterAgentToken`.
|
||||
|
||||
```graphql
|
||||
|
|
|
@ -12,7 +12,7 @@ type: howto
|
|||
GitLab lists all devices that have logged into your account. You can
|
||||
review the sessions, and revoke any you don't recognize.
|
||||
|
||||
## Listing all active sessions
|
||||
## List all active sessions
|
||||
|
||||
To list all active sessions:
|
||||
|
||||
|
@ -29,7 +29,7 @@ To list all active sessions:
|
|||
GitLab allows users to have up to 100 active sessions at once. If the number of active sessions
|
||||
exceeds 100, the oldest ones are deleted.
|
||||
|
||||
## Revoking a session
|
||||
## Revoke a session
|
||||
|
||||
To revoke an active session:
|
||||
|
||||
|
@ -40,7 +40,7 @@ To revoke an active session:
|
|||
|
||||
NOTE:
|
||||
When any session is revoked all **Remember me** tokens for all
|
||||
devices are revoked. See ['Why do I keep getting signed out?'](index.md#why-do-i-keep-getting-signed-out)
|
||||
devices are revoked. See [Why do I keep getting signed out?](index.md#why-do-i-keep-getting-signed-out)
|
||||
for more information about the **Remember me** feature.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
|
|
@ -260,6 +260,20 @@ To change your commit email:
|
|||
1. In the **Commit email** dropdown list, select an email address.
|
||||
1. Select **Update profile settings**.
|
||||
|
||||
## Change your primary email
|
||||
|
||||
Your primary email:
|
||||
|
||||
- Is the default email address for your login, commit email, and notification email.
|
||||
- Must be already [linked to your user profile](#add-emails-to-your-user-profile).
|
||||
|
||||
To change your primary email:
|
||||
|
||||
1. In the top-right corner, select your avatar.
|
||||
1. Select **Edit profile**.
|
||||
1. In the **Email** field, enter your new email address.
|
||||
1. Select **Update profile settings**.
|
||||
|
||||
### Use an automatically-generated private commit email
|
||||
|
||||
GitLab provides an automatically-generated private commit email address,
|
||||
|
|
|
@ -10,7 +10,12 @@ module BulkImports
|
|||
ndjson_pipeline!
|
||||
|
||||
def transform(context, data)
|
||||
return unless data
|
||||
|
||||
relation_hash, relation_index = data
|
||||
|
||||
return unless relation_hash
|
||||
|
||||
relation_definition = import_export_config.top_relation_tree(relation)
|
||||
|
||||
relation_object = deep_transform_relation!(relation_hash, relation, relation_definition) do |key, hash|
|
||||
|
|
|
@ -21,6 +21,7 @@ module Gitlab
|
|||
|
||||
from_union([failed_jobs, self.stuck])
|
||||
}
|
||||
scope :except_succeeded, -> { where(status: self.statuses.except(:succeeded).values) }
|
||||
|
||||
enum status: {
|
||||
pending: 0,
|
||||
|
|
|
@ -18,6 +18,8 @@ module Gitlab
|
|||
scope: [:job_class_name, :table_name, :column_name]
|
||||
}
|
||||
|
||||
validate :validate_batched_jobs_status, if: -> { status_changed? && finished? }
|
||||
|
||||
scope :queue_order, -> { order(id: :asc) }
|
||||
scope :queued, -> { where(status: [:active, :paused]) }
|
||||
scope :for_configuration, ->(job_class_name, table_name, column_name, job_arguments) do
|
||||
|
@ -133,6 +135,12 @@ module Gitlab
|
|||
def optimize!
|
||||
BatchOptimizer.new(self).optimize!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_batched_jobs_status
|
||||
errors.add(:batched_jobs, 'jobs need to be succeeded') if batched_jobs.except_succeeded.exists?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,7 +38,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def invite_members?
|
||||
invite_members_for_task_experiment_enabled?
|
||||
user.can?(:admin_group_member, group)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -166,16 +166,6 @@ module Gitlab
|
|||
link(s_('InProductMarketing|update your preferences'), preference_link)
|
||||
end
|
||||
|
||||
def invite_members_for_task_experiment_enabled?
|
||||
return unless user.can?(:admin_group_member, group)
|
||||
|
||||
experiment(:invite_members_for_task, namespace: group) do |e|
|
||||
e.candidate { true }
|
||||
e.record!
|
||||
e.run
|
||||
end
|
||||
end
|
||||
|
||||
def validate_series!
|
||||
raise ArgumentError, "Only #{total_series} series available for this track." unless @series.between?(0, total_series - 1)
|
||||
end
|
||||
|
|
|
@ -62,7 +62,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def invite_members?
|
||||
invite_members_for_task_experiment_enabled?
|
||||
user.can?(:admin_group_member, group)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -66,7 +66,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def invite_members?
|
||||
invite_members_for_task_experiment_enabled?
|
||||
user.can?(:admin_group_member, group)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -27032,6 +27032,9 @@ msgstr ""
|
|||
msgid "ProjectOverview|Unstar"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectOverview|You don't have permission to fork this project"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectOverview|You have reached your project limit"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -82,16 +82,6 @@ RSpec.describe GroupsController, factory_default: :keep do
|
|||
expect(subject).to redirect_to group_import_path(group)
|
||||
end
|
||||
end
|
||||
|
||||
context 'publishing the invite_members_for_task experiment' do
|
||||
it 'publishes the experiment data to the client' do
|
||||
wrapped_experiment(experiment(:invite_members_for_task)) do |e|
|
||||
expect(e).to receive(:publish_to_client)
|
||||
end
|
||||
|
||||
get :show, params: { id: group.to_param, open_modal: 'invite_members_for_task' }, format: format
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #details' do
|
||||
|
|
|
@ -101,10 +101,6 @@ RSpec.describe Registrations::WelcomeController do
|
|||
context 'when tasks to be done are assigned' do
|
||||
let!(:member1) { create(:group_member, user: user, tasks_to_be_done: %w(ci code)) }
|
||||
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to(issues_dashboard_path(assignee_username: user.username)) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,8 +5,6 @@ FactoryBot.define do
|
|||
sequence(:name) { |n| "namespace#{n}" }
|
||||
path { name.downcase.gsub(/\s/, '_') }
|
||||
|
||||
# TODO: can this be moved into the :user_namespace factory?
|
||||
# evaluate in issue https://gitlab.com/gitlab-org/gitlab/-/issues/341070
|
||||
owner { association(:user, strategy: :build, namespace: instance, username: path) }
|
||||
|
||||
trait :with_aggregation_schedule do
|
||||
|
|
|
@ -146,7 +146,7 @@ RSpec.describe "Issues > User edits issue", :js do
|
|||
fill_in 'Comment', with: '/label ~syzygy'
|
||||
|
||||
click_button 'Comment'
|
||||
expect(page).to have_text('added syzygy label just now')
|
||||
expect(page).to have_text('added syzygy label just now', wait: 300)
|
||||
|
||||
page.within '.block.labels' do
|
||||
# Remove `verisimilitude` label
|
||||
|
|
|
@ -59,10 +59,11 @@ RSpec.describe 'Project fork' do
|
|||
context 'forking is disabled' do
|
||||
let(:forking_access_level) { ProjectFeature::DISABLED }
|
||||
|
||||
it 'does not render fork button' do
|
||||
it 'render a disabled fork button' do
|
||||
visit project_path(project)
|
||||
|
||||
expect(page).not_to have_css('a', text: 'Fork')
|
||||
expect(page).to have_css('a.disabled', text: 'Fork')
|
||||
expect(page).to have_css('a.count', text: '0')
|
||||
end
|
||||
|
||||
it 'does not render new project fork page' do
|
||||
|
@ -80,10 +81,11 @@ RSpec.describe 'Project fork' do
|
|||
end
|
||||
|
||||
context 'user is not a team member' do
|
||||
it 'does not render fork button' do
|
||||
it 'render a disabled fork button' do
|
||||
visit project_path(project)
|
||||
|
||||
expect(page).not_to have_css('a', text: 'Fork')
|
||||
expect(page).to have_css('a.disabled', text: 'Fork')
|
||||
expect(page).to have_css('a.count', text: '0')
|
||||
end
|
||||
|
||||
it 'does not render new project fork page' do
|
||||
|
@ -102,6 +104,7 @@ RSpec.describe 'Project fork' do
|
|||
visit project_path(project)
|
||||
|
||||
expect(page).to have_css('a', text: 'Fork')
|
||||
expect(page).to have_css('a.count', text: '0')
|
||||
expect(page).not_to have_css('a.disabled', text: 'Fork')
|
||||
end
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ describe('Blob content viewer component', () => {
|
|||
const findForkSuggestion = () => wrapper.findComponent(ForkSuggestion);
|
||||
|
||||
beforeEach(() => {
|
||||
gon.features = { refactorTextViewer: true };
|
||||
gon.features = { highlightJs: true };
|
||||
isLoggedIn.mockReturnValue(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -93,22 +93,17 @@ RSpec.describe InviteMembersHelper do
|
|||
end
|
||||
end
|
||||
|
||||
context 'the invite_members_for_task experiment' do
|
||||
where(:invite_members_for_task_enabled?, :open_modal_param_present?, :logged_in?, :expected?) do
|
||||
true | true | true | true
|
||||
true | true | false | false
|
||||
true | false | true | false
|
||||
true | false | false | false
|
||||
false | true | true | false
|
||||
false | true | false | false
|
||||
false | false | true | false
|
||||
false | false | false | false
|
||||
context 'inviting members for tasks' do
|
||||
where(:open_modal_param_present?, :logged_in?, :expected?) do
|
||||
true | true | true
|
||||
true | false | false
|
||||
false | true | false
|
||||
false | false | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
allow(helper).to receive(:current_user).and_return(developer) if logged_in?
|
||||
stub_experiments(invite_members_for_task: true) if invite_members_for_task_enabled?
|
||||
allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) if open_modal_param_present?
|
||||
end
|
||||
|
||||
|
|
|
@ -991,4 +991,31 @@ RSpec.describe ProjectsHelper do
|
|||
expect(subject).to eq(project.path_with_namespace)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fork_button_disabled_tooltip' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
subject { helper.fork_button_disabled_tooltip(project) }
|
||||
|
||||
where(:has_user, :can_fork_project, :can_create_fork, :expected) do
|
||||
false | false | false | nil
|
||||
true | true | true | nil
|
||||
true | false | true | 'You don\'t have permission to fork this project'
|
||||
true | true | false | 'You have reached your project limit'
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
current_user = user if has_user
|
||||
|
||||
allow(helper).to receive(:current_user).and_return(current_user)
|
||||
allow(user).to receive(:can?).with(:fork_project, project).and_return(can_fork_project)
|
||||
allow(user).to receive(:can?).with(:create_fork).and_return(can_create_fork)
|
||||
end
|
||||
|
||||
it 'returns tooltip text when user lacks privilege' do
|
||||
expect(subject).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -130,6 +130,22 @@ RSpec.describe BulkImports::NdjsonPipeline do
|
|||
|
||||
subject.transform(context, data)
|
||||
end
|
||||
|
||||
context 'when data is nil' do
|
||||
before do
|
||||
expect(Gitlab::ImportExport::Group::RelationFactory).not_to receive(:create)
|
||||
end
|
||||
|
||||
it 'returns' do
|
||||
expect(subject.transform(nil, nil)).to be_nil
|
||||
end
|
||||
|
||||
context 'when relation hash is nil' do
|
||||
it 'returns' do
|
||||
expect(subject.transform(nil, [nil, 0])).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#load' do
|
||||
|
|
|
@ -17,15 +17,19 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
|
|||
let_it_be(:stuck_job) { create(:batched_background_migration_job, status: :pending, updated_at: fixed_time - described_class::STUCK_JOBS_TIMEOUT) }
|
||||
let_it_be(:failed_job) { create(:batched_background_migration_job, status: :failed, attempts: 1) }
|
||||
|
||||
before_all do
|
||||
create(:batched_background_migration_job, status: :failed, attempts: described_class::MAX_ATTEMPTS)
|
||||
create(:batched_background_migration_job, status: :succeeded)
|
||||
end
|
||||
let!(:max_attempts_failed_job) { create(:batched_background_migration_job, status: :failed, attempts: described_class::MAX_ATTEMPTS) }
|
||||
let!(:succeeded_job) { create(:batched_background_migration_job, status: :succeeded) }
|
||||
|
||||
before do
|
||||
travel_to fixed_time
|
||||
end
|
||||
|
||||
describe '.except_succeeded' do
|
||||
it 'returns not succeeded jobs' do
|
||||
expect(described_class.except_succeeded).to contain_exactly(pending_job, running_job, stuck_job, failed_job, max_attempts_failed_job)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.active' do
|
||||
it 'returns active jobs' do
|
||||
expect(described_class.active).to contain_exactly(pending_job, running_job, stuck_job)
|
||||
|
|
|
@ -23,6 +23,28 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
|
|||
subject { build(:batched_background_migration) }
|
||||
|
||||
it { is_expected.to validate_uniqueness_of(:job_arguments).scoped_to(:job_class_name, :table_name, :column_name) }
|
||||
|
||||
context 'when there are failed jobs' do
|
||||
let(:batched_migration) { create(:batched_background_migration, status: :active, total_tuple_count: 100) }
|
||||
let!(:batched_job) { create(:batched_background_migration_job, batched_migration: batched_migration, status: :failed) }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { batched_migration.finished! }.to raise_error(ActiveRecord::RecordInvalid)
|
||||
|
||||
expect(batched_migration.reload.status).to eql 'active'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the jobs are completed' do
|
||||
let(:batched_migration) { create(:batched_background_migration, status: :active, total_tuple_count: 100) }
|
||||
let!(:batched_job) { create(:batched_background_migration_job, batched_migration: batched_migration, status: :succeeded) }
|
||||
|
||||
it 'finishes the migration' do
|
||||
batched_migration.finished!
|
||||
|
||||
expect(batched_migration.status).to eql 'finished'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.queue_order' do
|
||||
|
|
|
@ -68,7 +68,6 @@ RSpec.describe Emails::InProductMarketing do
|
|||
|
||||
with_them do
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: :candidate)
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
|
|
|
@ -742,7 +742,6 @@ RSpec.describe Group do
|
|||
let!(:project) { create(:project, group: group) }
|
||||
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
group.add_users([create(:user)], :developer, tasks_to_be_done: %w(ci code), tasks_project_id: project.id)
|
||||
end
|
||||
|
||||
|
|
|
@ -681,8 +681,6 @@ RSpec.describe Member do
|
|||
end
|
||||
|
||||
it 'schedules a TasksToBeDone::CreateWorker task' do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
|
||||
member_task = create(:member_task, member: member, project: member.project)
|
||||
|
||||
expect(TasksToBeDone::CreateWorker)
|
||||
|
|
|
@ -237,7 +237,6 @@ RSpec.describe ProjectTeam do
|
|||
|
||||
context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
project.team.add_users([user1], :developer, tasks_to_be_done: %w(ci code), tasks_project_id: project.id)
|
||||
end
|
||||
|
||||
|
|
|
@ -167,10 +167,6 @@ RSpec.describe API::Invitations do
|
|||
end
|
||||
|
||||
context 'with tasks_to_be_done and tasks_project_id in the params' do
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
end
|
||||
|
||||
let(:project_id) { source_type == 'project' ? source.id : create(:project, namespace: source).id }
|
||||
|
||||
context 'when there is 1 invitation' do
|
||||
|
|
|
@ -415,10 +415,6 @@ RSpec.describe API::Members do
|
|||
end
|
||||
|
||||
context 'with tasks_to_be_done and tasks_project_id in the params' do
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
end
|
||||
|
||||
let(:project_id) { source_type == 'project' ? source.id : create(:project, namespace: source).id }
|
||||
|
||||
context 'when there is 1 user to add' do
|
||||
|
|
|
@ -202,10 +202,6 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_
|
|||
{ invite_source: '_invite_source_', tasks_to_be_done: %w(ci code), tasks_project_id: source.id }
|
||||
end
|
||||
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
end
|
||||
|
||||
it 'creates 2 task issues', :aggregate_failures do
|
||||
expect(TasksToBeDone::CreateWorker)
|
||||
.to receive(:perform_async)
|
||||
|
|
|
@ -301,10 +301,6 @@ RSpec.shared_examples_for "member creation" do
|
|||
end
|
||||
|
||||
context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
end
|
||||
|
||||
it 'creates a member_task with the correct attributes', :aggregate_failures do
|
||||
task_project = source.is_a?(Group) ? create(:project, group: source) : source
|
||||
described_class.new(source, user, :developer, tasks_to_be_done: %w(ci code), tasks_project_id: task_project.id).execute
|
||||
|
@ -397,10 +393,6 @@ RSpec.shared_examples_for "bulk member creation" do
|
|||
end
|
||||
|
||||
context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
|
||||
before do
|
||||
stub_experiments(invite_members_for_task: true)
|
||||
end
|
||||
|
||||
it 'creates a member_task with the correct attributes', :aggregate_failures do
|
||||
task_project = source.is_a?(Group) ? create(:project, group: source) : source
|
||||
members = described_class.add_users(source, [user1], :developer, tasks_to_be_done: %w(ci code), tasks_project_id: task_project.id)
|
||||
|
|
Loading…
Reference in a new issue