Commit 605d78c9 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents c28d09bd 43afd667
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
## Author's checklist (required) ## Author's checklist (required)
- [ ] Follow the [Documentation Guidelines](https://docs.gitlab.com/ee/development/documentation/) and [Style Guide](https://docs.gitlab.com/ee/development/documentation/styleguide.html). - [ ] Follow the [Documentation Guidelines](https://docs.gitlab.com/ee/development/documentation/) and [Style Guide](https://docs.gitlab.com/ee/development/documentation/styleguide.html).
- If you have **Developer** permissions or higher: - If you have **Developer** permissions or higher:
- [ ] Ensure that the [product tier badge](https://docs.gitlab.com/ee/development/documentation/styleguide.html#product-badges) is added to doc's `h1`. - [ ] Ensure that the [product tier badge](https://docs.gitlab.com/ee/development/documentation/styleguide.html#product-badges) is added to doc's `h1`.
- [ ] Apply the ~documentation label, plus: - [ ] Apply the ~documentation label, plus:
- The corresponding DevOps stage and group labels, if applicable. - The corresponding DevOps stage and group labels, if applicable.
- ~"development guidelines" when changing docs under `doc/development/*`, `CONTRIBUTING.md`, or `README.md`. - ~"development guidelines" when changing docs under `doc/development/*`, `CONTRIBUTING.md`, or `README.md`.
......
...@@ -427,6 +427,8 @@ class ApplicationSetting < ApplicationRecord ...@@ -427,6 +427,8 @@ class ApplicationSetting < ApplicationRecord
end end
def self.create_from_defaults def self.create_from_defaults
check_schema!
transaction(requires_new: true) do transaction(requires_new: true) do
super super
end end
...@@ -435,6 +437,22 @@ class ApplicationSetting < ApplicationRecord ...@@ -435,6 +437,22 @@ class ApplicationSetting < ApplicationRecord
current_without_cache current_without_cache
end end
# Due to the frequency with which settings are accessed, it is
# likely that during a backup restore a running GitLab process
# will insert a new `application_settings` row before the
# constraints have been added to the table. This would add an
# extra row with ID 1 and prevent the primary key constraint from
# being added, which made ActiveRecord throw a
# IrreversibleOrderError anytime the settings were accessed
# (https://gitlab.com/gitlab-org/gitlab/-/issues/36405). To
# prevent this from happening, we do a sanity check that the
# primary key constraint is present before inserting a new entry.
def self.check_schema!
return if ActiveRecord::Base.connection.primary_key(self.table_name).present?
raise "The `#{self.table_name}` table is missing a primary key constraint in the database schema"
end
# By default, the backend is Rails.cache, which uses # By default, the backend is Rails.cache, which uses
# ActiveSupport::Cache::RedisStore. Since loading ApplicationSetting # ActiveSupport::Cache::RedisStore. Since loading ApplicationSetting
# can cause a significant amount of load on Redis, let's cache it in # can cause a significant amount of load on Redis, let's cache it in
......
...@@ -199,7 +199,14 @@ class CommitStatus < ApplicationRecord ...@@ -199,7 +199,14 @@ class CommitStatus < ApplicationRecord
end end
def group_name def group_name
name.to_s.gsub(%r{\d+[\s:/\\]+\d+\s*}, '').strip # 'rspec:linux: 1/10' => 'rspec:linux'
common_name = name.to_s.gsub(%r{\d+[\s:\/\\]+\d+\s*}, '')
# 'rspec:linux: [aws, max memory]' => 'rspec:linux'
common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '') if Gitlab::Ci::Features.new_matrix_job_names_enabled?
common_name.strip!
common_name
end end
def failed_but_allowed? def failed_but_allowed?
......
---
title: Upgrade pages to v1.23.0
merge_request: 40915
author:
type: added
---
title: Fix ActiveRecord::IrreversibleOrderError during restore from backup
merge_request: 40789
author:
type: fixed
# Import bare repositories **(CORE ONLY)** # Import bare repositories **(CORE ONLY)**
Rake tasks are available to import bare repositories into a GitLab instance. Rake tasks are available to import bare repositories into a GitLab instance.
When migrating from an existing GitLab instance,
and to preserve ownership by users and their namespaces,
please use [our project-based import/export](../user/project/settings/import_export.md).
Note that: Note that:
...@@ -14,11 +17,14 @@ Note that: ...@@ -14,11 +17,14 @@ Note that:
To import bare repositories into a GitLab instance: To import bare repositories into a GitLab instance:
1. Create a new folder to import your Git repositories from. The new folder needs to have Git user 1. Create a new folder to import your Git repositories from.
ownership and read/write/execute access for Git user and its group: You can also import projects into a (sub)group's namespace,
instead of the administrator's namespace. To do so, create subfolders and
give ownership and read/write/execute permissions of those subfolders to the
`git` user and its group:
```shell ```shell
sudo -u git mkdir -p /var/opt/gitlab/git-data/repository-import-<date>/new_group sudo -u git mkdir -p /var/opt/gitlab/git-data/repository-import-$(date "+%Y-%m-%d")/<optional_groupname>/<optional_subgroup>
``` ```
1. Copy your bare repositories inside this newly created folder. Note: 1. Copy your bare repositories inside this newly created folder. Note:
...@@ -26,15 +32,15 @@ To import bare repositories into a GitLab instance: ...@@ -26,15 +32,15 @@ To import bare repositories into a GitLab instance:
- Any `.git` repositories found on any of the subfolders will be imported as projects. - Any `.git` repositories found on any of the subfolders will be imported as projects.
- Groups will be created as needed, these could be nested folders. - Groups will be created as needed, these could be nested folders.
For example, if we copy the repositories to `/var/opt/gitlab/git-data/repository-import-<date>`, For example, if we copy the repositories to `/var/opt/gitlab/git-data/repository-import-2020-08-22`,
and repository `A` needs to be under the groups `G1` and `G2`, it must be created under those folders: and repository `A` needs to be under the groups `G1` and `G2`, it must be created under those folders:
`/var/opt/gitlab/git-data/repository-import-<date>/G1/G2/A.git`. `/var/opt/gitlab/git-data/repository-import-2020-08-22/G1/G2/A.git`.
```shell ```shell
sudo cp -r /old/git/foo.git /var/opt/gitlab/git-data/repository-import-<date>/new_group/ sudo cp -r /old/git/foo.git /var/opt/gitlab/git-data/repository-import-$(date "+%Y-%m-%d")/<optional_groupname>/<optional_subgroup>
# Do this once when you are done copying git repositories # Do this once when you are done copying git repositories
sudo chown -R git:git /var/opt/gitlab/git-data/repository-import-<date> sudo chown -R git:git /var/opt/gitlab/git-data/repository-import-$(date "+%Y-%m-%d")
``` ```
`foo.git` needs to be owned by the `git` user and `git` users group. `foo.git` needs to be owned by the `git` user and `git` users group.
...@@ -46,7 +52,7 @@ To import bare repositories into a GitLab instance: ...@@ -46,7 +52,7 @@ To import bare repositories into a GitLab instance:
- Omnibus Installation - Omnibus Installation
```shell ```shell
sudo gitlab-rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-<date>'] sudo gitlab-rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-$(date "+%Y-%m-%d")']
``` ```
- Installation from source. Before running this command you need to change to the directory where - Installation from source. Before running this command you need to change to the directory where
...@@ -54,7 +60,7 @@ To import bare repositories into a GitLab instance: ...@@ -54,7 +60,7 @@ To import bare repositories into a GitLab instance:
```shell ```shell
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-<date>'] RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-$(date "+%Y-%m-%d")'] RAILS_ENV=production
``` ```
## Example output ## Example output
......
...@@ -13,6 +13,9 @@ For more details, see [Bulk editing issues and merge requests at the project lev ...@@ -13,6 +13,9 @@ For more details, see [Bulk editing issues and merge requests at the project lev
If you want to update attributes across multiple issues, epics, or merge requests in a group, you If you want to update attributes across multiple issues, epics, or merge requests in a group, you
can do it by bulk editing them, that is, editing them together. can do it by bulk editing them, that is, editing them together.
NOTE: **Note:**
Only the items visible on the current page are selected for bulk editing (up to 20).
![Bulk editing](img/bulk-editing_v13_2.png) ![Bulk editing](img/bulk-editing_v13_2.png)
## Bulk edit issues at the group level ## Bulk edit issues at the group level
......
...@@ -14,6 +14,9 @@ For more details, see ...@@ -14,6 +14,9 @@ For more details, see
If you want to update attributes across multiple issues or merge requests, you can do it If you want to update attributes across multiple issues or merge requests, you can do it
by bulk editing them, that is, editing them together. by bulk editing them, that is, editing them together.
NOTE: **Note:**
Only the items visible on the current page are selected for bulk editing (up to 20).
![Bulk editing](img/bulk-editing_v13_2.png) ![Bulk editing](img/bulk-editing_v13_2.png)
## Bulk edit issues at the project level ## Bulk edit issues at the project level
......
// Node spec helpers // Node spec helpers
export const buildMockTextNode = literal => { export const buildMockTextNode = literal => ({ literal, type: 'text' });
return {
firstChild: null,
literal,
type: 'text',
};
};
export const normalTextNode = buildMockTextNode('This is just normal text.'); export const normalTextNode = buildMockTextNode('This is just normal text.');
...@@ -23,17 +17,20 @@ const buildMockUneditableOpenToken = type => { ...@@ -23,17 +17,20 @@ const buildMockUneditableOpenToken = type => {
}; };
}; };
const buildMockUneditableCloseToken = type => { const buildMockTextToken = content => {
return { type: 'closeTag', tagName: type }; return {
type: 'text',
tagName: null,
content,
};
}; };
export const originToken = { const buildMockUneditableCloseToken = type => ({ type: 'closeTag', tagName: type });
type: 'text',
tagName: null, export const originToken = buildMockTextToken('{:.no_toc .hidden-md .hidden-lg}');
content: '{:.no_toc .hidden-md .hidden-lg}', const uneditableOpenToken = buildMockUneditableOpenToken('div');
}; export const uneditableOpenTokens = [uneditableOpenToken, originToken];
export const uneditableCloseToken = buildMockUneditableCloseToken('div'); export const uneditableCloseToken = buildMockUneditableCloseToken('div');
export const uneditableOpenTokens = [buildMockUneditableOpenToken('div'), originToken];
export const uneditableCloseTokens = [originToken, uneditableCloseToken]; export const uneditableCloseTokens = [originToken, uneditableCloseToken];
export const uneditableTokens = [...uneditableOpenTokens, uneditableCloseToken]; export const uneditableTokens = [...uneditableOpenTokens, uneditableCloseToken];
...@@ -41,6 +38,7 @@ export const originInlineToken = { ...@@ -41,6 +38,7 @@ export const originInlineToken = {
type: 'text', type: 'text',
content: '<i>Inline</i> content', content: '<i>Inline</i> content',
}; };
export const uneditableInlineTokens = [ export const uneditableInlineTokens = [
buildMockUneditableOpenToken('a'), buildMockUneditableOpenToken('a'),
originInlineToken, originInlineToken,
...@@ -48,13 +46,9 @@ export const uneditableInlineTokens = [ ...@@ -48,13 +46,9 @@ export const uneditableInlineTokens = [
]; ];
export const uneditableBlockTokens = [ export const uneditableBlockTokens = [
buildMockUneditableOpenToken('div'), uneditableOpenToken,
{ buildMockTextToken('<div><h1>Some header</h1><p>Some paragraph</p></div>'),
type: 'text', uneditableCloseToken,
tagName: null,
content: '<div><h1>Some header</h1><p>Some paragraph</p></div>',
},
buildMockUneditableCloseToken('div'),
]; ];
export const attributeDefinition = '{:.no_toc .hidden-md .hidden-lg}'; export const attributeDefinition = '{:.no_toc .hidden-md .hidden-lg}';
...@@ -115,6 +115,16 @@ RSpec.describe Gitlab::CurrentSettings do ...@@ -115,6 +115,16 @@ RSpec.describe Gitlab::CurrentSettings do
expect(settings).to have_attributes(settings_from_defaults) expect(settings).to have_attributes(settings_from_defaults)
end end
context 'when ApplicationSettings does not have a primary key' do
before do
allow(ActiveRecord::Base.connection).to receive(:primary_key).with('application_settings').and_return(nil)
end
it 'raises an exception if ApplicationSettings does not have a primary key' do
expect { described_class.current_application_settings }.to raise_error(/table is missing a primary key constraint/)
end
end
context 'with pending migrations' do context 'with pending migrations' do
let(:current_settings) { described_class.current_application_settings } let(:current_settings) { described_class.current_application_settings }
......
...@@ -650,6 +650,16 @@ RSpec.describe ApplicationSetting do ...@@ -650,6 +650,16 @@ RSpec.describe ApplicationSetting do
end end
end end
context 'when ApplicationSettings does not have a primary key' do
before do
allow(ActiveRecord::Base.connection).to receive(:primary_key).with(described_class.table_name).and_return(nil)
end
it 'raises an exception' do
expect { described_class.create_from_defaults }.to raise_error(/table is missing a primary key constraint/)
end
end
describe '#disabled_oauth_sign_in_sources=' do describe '#disabled_oauth_sign_in_sources=' do
before do before do
allow(Devise).to receive(:omniauth_providers).and_return([:github]) allow(Devise).to receive(:omniauth_providers).and_return([:github])
......
...@@ -494,6 +494,10 @@ RSpec.describe CommitStatus do ...@@ -494,6 +494,10 @@ RSpec.describe CommitStatus do
end end
describe '#group_name' do describe '#group_name' do
let(:commit_status) do
build(:commit_status, pipeline: pipeline, stage: 'test')
end
subject { commit_status.group_name } subject { commit_status.group_name }
tests = { tests = {
...@@ -510,7 +514,19 @@ RSpec.describe CommitStatus do ...@@ -510,7 +514,19 @@ RSpec.describe CommitStatus do
'rspec:windows 0 : / 1' => 'rspec:windows', 'rspec:windows 0 : / 1' => 'rspec:windows',
'rspec:windows 0 : / 1 name' => 'rspec:windows name', 'rspec:windows 0 : / 1 name' => 'rspec:windows name',
'0 1 name ruby' => 'name ruby', '0 1 name ruby' => 'name ruby',
'0 :/ 1 name ruby' => 'name ruby' '0 :/ 1 name ruby' => 'name ruby',
'rspec: [aws]' => 'rspec: [aws]',
'rspec: [aws] 0/1' => 'rspec: [aws]',
'rspec: [aws, max memory]' => 'rspec',
'rspec:linux: [aws, max memory, data]' => 'rspec:linux',
'rspec: [inception: [something, other thing], value]' => 'rspec',
'rspec:windows 0/1: [name, other]' => 'rspec:windows',
'rspec:windows: [name, other] 0/1' => 'rspec:windows',
'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows',
'rspec:windows: [0/1, name]' => 'rspec:windows',
'rspec:windows: [, ]' => 'rspec:windows',
'rspec:windows: [name]' => 'rspec:windows: [name]',
'rspec:windows: [name,other]' => 'rspec:windows: [name,other]'
} }
tests.each do |name, group_name| tests.each do |name, group_name|
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment