Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
179b33c546
commit
b132e99b27
19 changed files with 183 additions and 28 deletions
|
@ -6,6 +6,7 @@ import {
|
|||
isInFuture,
|
||||
isInPast,
|
||||
isToday,
|
||||
newDateAsLocaleTime,
|
||||
} from '~/lib/utils/datetime_utility';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
|
@ -27,7 +28,7 @@ export default {
|
|||
milestoneDate() {
|
||||
if (this.issue.milestone?.dueDate) {
|
||||
const { dueDate, startDate } = this.issue.milestone;
|
||||
const date = dateInWords(new Date(dueDate), true);
|
||||
const date = dateInWords(newDateAsLocaleTime(dueDate), true);
|
||||
const remainingTime = this.milestoneRemainingTime(dueDate, startDate);
|
||||
return `${date} (${remainingTime})`;
|
||||
}
|
||||
|
@ -37,10 +38,10 @@ export default {
|
|||
return this.issue.milestone.webPath || this.issue.milestone.webUrl;
|
||||
},
|
||||
dueDate() {
|
||||
return this.issue.dueDate && dateInWords(new Date(this.issue.dueDate), true);
|
||||
return this.issue.dueDate && dateInWords(newDateAsLocaleTime(this.issue.dueDate), true);
|
||||
},
|
||||
showDueDateInRed() {
|
||||
return isInPast(new Date(this.issue.dueDate)) && !this.issue.closedAt;
|
||||
return isInPast(newDateAsLocaleTime(this.issue.dueDate)) && !this.issue.closedAt;
|
||||
},
|
||||
timeEstimate() {
|
||||
return this.issue.humanTimeEstimate || this.issue.timeStats?.humanTimeEstimate;
|
||||
|
@ -48,8 +49,8 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
milestoneRemainingTime(dueDate, startDate) {
|
||||
const due = new Date(dueDate);
|
||||
const start = new Date(startDate);
|
||||
const due = newDateAsLocaleTime(dueDate);
|
||||
const start = newDateAsLocaleTime(startDate);
|
||||
|
||||
if (dueDate && isInPast(due)) {
|
||||
return __('Past due');
|
||||
|
|
|
@ -189,13 +189,21 @@ export const getDateInFuture = (date, daysInFuture) =>
|
|||
*/
|
||||
export const isValidDate = (date) => date instanceof Date && !Number.isNaN(date.getTime());
|
||||
|
||||
/*
|
||||
/**
|
||||
* Appending T00:00:00 makes JS assume local time and prevents it from shifting the date
|
||||
* to match the user's time zone. We want to display the date in server time for now, to
|
||||
* be consistent with the "edit issue -> due date" UI.
|
||||
*
|
||||
* @param {String} date Date without time, e.g. `2022-03-22`
|
||||
* @return {Date} new Date object
|
||||
*/
|
||||
|
||||
export const newDateAsLocaleTime = (date) => {
|
||||
if (!date || typeof date !== 'string') {
|
||||
return null;
|
||||
}
|
||||
if (date.includes('T')) {
|
||||
return new Date(date);
|
||||
}
|
||||
const suffix = 'T00:00:00';
|
||||
return new Date(`${date}${suffix}`);
|
||||
};
|
||||
|
|
|
@ -609,6 +609,7 @@ class ApplicationSetting < ApplicationRecord
|
|||
attr_encrypted :cloud_license_auth_token, encryption_options_base_32_aes_256_gcm
|
||||
attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_32_aes_256_gcm
|
||||
attr_encrypted :mailgun_signing_key, encryption_options_base_32_aes_256_gcm.merge(encode: false)
|
||||
attr_encrypted :database_grafana_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
|
||||
|
||||
validates :disable_feed_token,
|
||||
inclusion: { in: [true, false], message: _('must be a boolean value') }
|
||||
|
|
|
@ -26,4 +26,8 @@ class BaseContainerService
|
|||
def group_container?
|
||||
container.is_a?(::Group)
|
||||
end
|
||||
|
||||
def namespace_container?
|
||||
container.is_a?(::Namespace)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: arkose_labs_login_challenge
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82751
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356171
|
||||
milestone: '14.10'
|
||||
type: development
|
||||
group: group::antiabuse
|
||||
default_enabled: false
|
|
@ -989,6 +989,14 @@ Settings['prometheus'] ||= Settingslogic.new({})
|
|||
Settings.prometheus['enabled'] ||= false
|
||||
Settings.prometheus['server_address'] ||= nil
|
||||
|
||||
#
|
||||
# Arkose settings
|
||||
#
|
||||
Settings['arkose'] ||= Settingslogic.new({})
|
||||
Settings.arkose['public_key'] ||= ENV['ARKOSE_LABS_PUBLIC_KEY']
|
||||
Settings.arkose['private_key'] ||= ENV['ARKOSE_LABS_PRIVATE_KEY']
|
||||
Settings.arkose['verify_url'] ||= ENV['ARKOSE_LABS_VERIFY_URL']
|
||||
|
||||
#
|
||||
# Shutdown settings
|
||||
#
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDatabaseGrafanaConfigToApplicationSettings < Gitlab::Database::Migration[1.0]
|
||||
# rubocop:disable Migration/AddLimitToTextColumns
|
||||
# limit is added in 20220307002607_add_text_limit_to_db_reindexing_grafana_application_settings
|
||||
def change
|
||||
add_column :application_settings, :encrypted_database_grafana_api_key, :binary
|
||||
add_column :application_settings, :encrypted_database_grafana_api_key_iv, :binary
|
||||
add_column :application_settings, :database_grafana_api_url, :text
|
||||
add_column :application_settings, :database_grafana_tag, :text
|
||||
end
|
||||
# rubocop:enable Migration/AddLimitToTextColumns
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTextLimitToDatabaseGrafanaApplicationSettings < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_text_limit :application_settings, :database_grafana_api_url, 255
|
||||
add_text_limit :application_settings, :database_grafana_tag, 255
|
||||
end
|
||||
|
||||
def down
|
||||
remove_text_limit :application_settings, :database_grafana_tag
|
||||
remove_text_limit :application_settings, :database_grafana_api_url
|
||||
end
|
||||
end
|
1
db/schema_migrations/20220310011530
Normal file
1
db/schema_migrations/20220310011530
Normal file
|
@ -0,0 +1 @@
|
|||
a4245a3543796b48f16786e9c178f70d236b3ae4636661f021ad4e8f0c678f2c
|
1
db/schema_migrations/20220310011613
Normal file
1
db/schema_migrations/20220310011613
Normal file
|
@ -0,0 +1 @@
|
|||
ef816d9391d67a34121d11e6b6cc37de92768bd21bc301fa10c6652b1a0b66b6
|
|
@ -11253,6 +11253,10 @@ CREATE TABLE application_settings (
|
|||
container_registry_expiration_policies_caching boolean DEFAULT true NOT NULL,
|
||||
search_rate_limit integer DEFAULT 30 NOT NULL,
|
||||
search_rate_limit_unauthenticated integer DEFAULT 10 NOT NULL,
|
||||
encrypted_database_grafana_api_key bytea,
|
||||
encrypted_database_grafana_api_key_iv bytea,
|
||||
database_grafana_api_url text,
|
||||
database_grafana_tag text,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
|
||||
|
@ -11261,8 +11265,10 @@ CREATE TABLE application_settings (
|
|||
CONSTRAINT app_settings_yaml_max_depth_positive CHECK ((max_yaml_depth > 0)),
|
||||
CONSTRAINT app_settings_yaml_max_size_positive CHECK ((max_yaml_size_bytes > 0)),
|
||||
CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
|
||||
CONSTRAINT check_2b820eaac3 CHECK ((char_length(database_grafana_tag) <= 255)),
|
||||
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
|
||||
CONSTRAINT check_32710817e9 CHECK ((char_length(static_objects_external_storage_auth_token_encrypted) <= 255)),
|
||||
CONSTRAINT check_3455368420 CHECK ((char_length(database_grafana_api_url) <= 255)),
|
||||
CONSTRAINT check_3559645ae5 CHECK ((char_length(container_registry_import_target_plan) <= 255)),
|
||||
CONSTRAINT check_3def0f1829 CHECK ((char_length(sentry_clientside_dsn) <= 255)),
|
||||
CONSTRAINT check_4f8b811780 CHECK ((char_length(sentry_dsn) <= 255)),
|
||||
|
|
|
@ -4336,7 +4336,7 @@ Input type: `ScanExecutionPolicyCommitInput`
|
|||
|
||||
### `Mutation.securityPolicyProjectAssign`
|
||||
|
||||
Assigns the specified project(`security_policy_project_id`) as security policy project for the given project(`project_path`). If the project already has a security policy project, this reassigns the project's security policy project with the given `security_policy_project_id`.
|
||||
Assigns the specified project(`security_policy_project_id`) as security policy project for the given project(`full_path`). If the project already has a security policy project, this reassigns the project's security policy project with the given `security_policy_project_id`.
|
||||
|
||||
Input type: `SecurityPolicyProjectAssignInput`
|
||||
|
||||
|
@ -4345,7 +4345,8 @@ Input type: `SecurityPolicyProjectAssignInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationsecuritypolicyprojectassignclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationsecuritypolicyprojectassignprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
|
||||
| <a id="mutationsecuritypolicyprojectassignfullpath"></a>`fullPath` | [`String`](#string) | Full path of the project. |
|
||||
| <a id="mutationsecuritypolicyprojectassignprojectpath"></a>`projectPath` **{warning-solid}** | [`ID`](#id) | **Deprecated:** Use `fullPath`. Deprecated in 14.10. |
|
||||
| <a id="mutationsecuritypolicyprojectassignsecuritypolicyprojectid"></a>`securityPolicyProjectId` | [`ProjectID!`](#projectid) | ID of the security policy project. |
|
||||
|
||||
#### Fields
|
||||
|
@ -4357,7 +4358,7 @@ Input type: `SecurityPolicyProjectAssignInput`
|
|||
|
||||
### `Mutation.securityPolicyProjectCreate`
|
||||
|
||||
Creates and assigns a security policy project for the given project(`project_path`).
|
||||
Creates and assigns a security policy project for the given project (`full_path`).
|
||||
|
||||
Input type: `SecurityPolicyProjectCreateInput`
|
||||
|
||||
|
@ -4366,7 +4367,8 @@ Input type: `SecurityPolicyProjectCreateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationsecuritypolicyprojectcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationsecuritypolicyprojectcreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
|
||||
| <a id="mutationsecuritypolicyprojectcreatefullpath"></a>`fullPath` | [`String`](#string) | Full path of the project. |
|
||||
| <a id="mutationsecuritypolicyprojectcreateprojectpath"></a>`projectPath` **{warning-solid}** | [`ID`](#id) | **Deprecated:** Use `fullPath`. Deprecated in 14.10. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ module Gitlab
|
|||
module Reindexing
|
||||
# This can be used to send annotations for reindexing to a Grafana API
|
||||
class GrafanaNotifier
|
||||
def initialize(api_key = ENV['GITLAB_GRAFANA_API_KEY'], api_url = ENV['GITLAB_GRAFANA_API_URL'], additional_tag = ENV['GITLAB_REINDEXING_GRAFANA_TAG'] || Rails.env)
|
||||
@api_key = api_key
|
||||
@api_url = api_url
|
||||
@additional_tag = additional_tag
|
||||
def initialize(api_key: nil, api_url: nil, additional_tag: nil)
|
||||
@api_key = api_key || default_api_key
|
||||
@api_url = api_url || default_api_url
|
||||
@additional_tag = additional_tag || default_additional_tag
|
||||
end
|
||||
|
||||
def notify_start(action)
|
||||
|
@ -35,10 +35,22 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def default_api_key
|
||||
Gitlab::CurrentSettings.database_grafana_api_key || ENV['GITLAB_GRAFANA_API_KEY']
|
||||
end
|
||||
|
||||
def default_api_url
|
||||
Gitlab::CurrentSettings.database_grafana_api_url || ENV['GITLAB_GRAFANA_API_URL']
|
||||
end
|
||||
|
||||
def default_additional_tag
|
||||
Gitlab::CurrentSettings.database_grafana_tag || ENV['GITLAB_REINDEXING_GRAFANA_TAG'] || Rails.env
|
||||
end
|
||||
|
||||
def base_payload(action)
|
||||
{
|
||||
time: (action.action_start.utc.to_f * 1000).to_i,
|
||||
tags: ['reindex', @additional_tag, action.index.tablename, action.index.name].compact
|
||||
tags: ['reindex', @additional_tag.presence, action.index.tablename, action.index.name].compact
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -10309,7 +10309,7 @@ msgstr ""
|
|||
msgid "Could not upload your designs as one or more files uploaded are not supported."
|
||||
msgstr ""
|
||||
|
||||
msgid "Couldn't assign policy to project"
|
||||
msgid "Couldn't assign policy to project or group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Country"
|
||||
|
|
|
@ -193,6 +193,10 @@ RSpec.describe SessionsController do
|
|||
end
|
||||
|
||||
context 'with reCAPTCHA' do
|
||||
before do
|
||||
stub_feature_flags(arkose_labs_login_challenge: false)
|
||||
end
|
||||
|
||||
def unsuccesful_login(user_params, sesion_params: {})
|
||||
# Without this, `verify_recaptcha` arbitrarily returns true in test env
|
||||
Recaptcha.configuration.skip_verify_env.delete('test')
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useFakeDate } from 'helpers/fake_date';
|
|||
import IssueCardTimeInfo from '~/issues/list/components/issue_card_time_info.vue';
|
||||
|
||||
describe('CE IssueCardTimeInfo component', () => {
|
||||
useFakeDate(2020, 11, 11);
|
||||
useFakeDate(2020, 11, 11); // 2020 Dec 11
|
||||
|
||||
let wrapper;
|
||||
|
||||
|
@ -91,7 +91,7 @@ describe('CE IssueCardTimeInfo component', () => {
|
|||
describe('when in the past', () => {
|
||||
describe('when issue is open', () => {
|
||||
it('renders in red', () => {
|
||||
wrapper = mountComponent({ dueDate: new Date('2020-10-10') });
|
||||
wrapper = mountComponent({ dueDate: '2020-10-10' });
|
||||
|
||||
expect(findDueDate().classes()).toContain('gl-text-red-500');
|
||||
});
|
||||
|
@ -100,7 +100,7 @@ describe('CE IssueCardTimeInfo component', () => {
|
|||
describe('when issue is closed', () => {
|
||||
it('does not render in red', () => {
|
||||
wrapper = mountComponent({
|
||||
dueDate: new Date('2020-10-10'),
|
||||
dueDate: '2020-10-10',
|
||||
closedAt: '2020-09-05T13:06:25Z',
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { newDateAsLocaleTime } from '~/lib/utils/datetime/date_calculation_utility';
|
||||
|
||||
describe('newDateAsLocaleTime', () => {
|
||||
it.each`
|
||||
string | expected
|
||||
${'2022-03-22'} | ${new Date('2022-03-22T00:00:00.000Z')}
|
||||
${'2022-03-22T00:00:00.000Z'} | ${new Date('2022-03-22T00:00:00.000Z')}
|
||||
${2022} | ${null}
|
||||
${[]} | ${null}
|
||||
${{}} | ${null}
|
||||
${true} | ${null}
|
||||
${null} | ${null}
|
||||
${undefined} | ${null}
|
||||
`('returns $expected given $string', ({ string, expected }) => {
|
||||
expect(newDateAsLocaleTime(string)).toEqual(expected);
|
||||
});
|
||||
});
|
|
@ -74,8 +74,28 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do
|
|||
end
|
||||
|
||||
describe '#notify_start' do
|
||||
context 'additional tag is nil' do
|
||||
subject { described_class.new(api_key, api_url, nil).notify_start(action) }
|
||||
context 'when Grafana is configured using application settings' do
|
||||
subject { described_class.new.notify_start(action) }
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
time: (action.action_start.utc.to_f * 1000).to_i,
|
||||
tags: ['reindex', additional_tag, action.index.tablename, action.index.name],
|
||||
text: "Started reindexing of #{action.index.name} on #{action.index.tablename}"
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_application_setting(database_grafana_api_key: api_key)
|
||||
stub_application_setting(database_grafana_api_url: api_url)
|
||||
stub_application_setting(database_grafana_tag: additional_tag)
|
||||
end
|
||||
|
||||
it_behaves_like 'interacting with Grafana annotations API'
|
||||
end
|
||||
|
||||
context 'when there is no additional tag' do
|
||||
subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: '').notify_start(action) }
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
|
@ -88,8 +108,8 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do
|
|||
it_behaves_like 'interacting with Grafana annotations API'
|
||||
end
|
||||
|
||||
context 'additional tag is not nil' do
|
||||
subject { described_class.new(api_key, api_url, additional_tag).notify_start(action) }
|
||||
context 'additional tag is provided' do
|
||||
subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: additional_tag).notify_start(action) }
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
|
@ -104,8 +124,30 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do
|
|||
end
|
||||
|
||||
describe '#notify_end' do
|
||||
context 'additional tag is nil' do
|
||||
subject { described_class.new(api_key, api_url, nil).notify_end(action) }
|
||||
context 'when Grafana is configured using application settings' do
|
||||
subject { described_class.new.notify_end(action) }
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
time: (action.action_start.utc.to_f * 1000).to_i,
|
||||
tags: ['reindex', additional_tag, action.index.tablename, action.index.name],
|
||||
text: "Finished reindexing of #{action.index.name} on #{action.index.tablename} (#{action.state})",
|
||||
timeEnd: (action.action_end.utc.to_f * 1000).to_i,
|
||||
isRegion: true
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_application_setting(database_grafana_api_key: api_key)
|
||||
stub_application_setting(database_grafana_api_url: api_url)
|
||||
stub_application_setting(database_grafana_tag: additional_tag)
|
||||
end
|
||||
|
||||
it_behaves_like 'interacting with Grafana annotations API'
|
||||
end
|
||||
|
||||
context 'when there is no additional tag' do
|
||||
subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: '').notify_end(action) }
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
|
@ -120,8 +162,8 @@ RSpec.describe Gitlab::Database::Reindexing::GrafanaNotifier do
|
|||
it_behaves_like 'interacting with Grafana annotations API'
|
||||
end
|
||||
|
||||
context 'additional tag is not nil' do
|
||||
subject { described_class.new(api_key, api_url, additional_tag).notify_end(action) }
|
||||
context 'additional tag is provided' do
|
||||
subject { described_class.new(api_key: api_key, api_url: api_url, additional_tag: additional_tag).notify_end(action) }
|
||||
|
||||
let(:payload) do
|
||||
{
|
||||
|
|
|
@ -1306,4 +1306,16 @@ RSpec.describe ApplicationSetting do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#database_grafana_api_key' do
|
||||
it 'is encrypted' do
|
||||
subject.database_grafana_api_key = 'somesecret'
|
||||
|
||||
aggregate_failures do
|
||||
expect(subject.encrypted_database_grafana_api_key).to be_present
|
||||
expect(subject.encrypted_database_grafana_api_key_iv).to be_present
|
||||
expect(subject.encrypted_database_grafana_api_key).not_to eq(subject.database_grafana_api_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue