提交 72721699 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 06be418a
import initSettingsPanels from '~/settings_panels';
document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels
initSettingsPanels();
const domainCard = document.querySelector('.js-domain-cert-show');
const domainForm = document.querySelector('.js-domain-cert-inputs');
const domainReplaceButton = document.querySelector('.js-domain-cert-replace-btn');
const domainSubmitButton = document.querySelector('.js-serverless-domain-submit');
if (domainReplaceButton && domainCard && domainForm) {
domainReplaceButton.addEventListener('click', () => {
domainCard.classList.add('hidden');
domainForm.classList.remove('hidden');
domainSubmitButton.removeAttribute('disabled');
});
}
});
......@@ -56,4 +56,15 @@
border-top-right-radius: $border-radius-default;
}
&.floating-status-badge {
position: absolute;
right: $gl-padding-24;
bottom: $gl-padding-4;
margin-bottom: 0;
}
}
.form-control.has-floating-status-badge {
position: relative;
padding-right: 120px;
}
# frozen_string_literal: true
class Admin::Serverless::DomainsController < Admin::ApplicationController
before_action :check_feature_flag
before_action :domain, only: [:update, :verify]
def index
@domain = PagesDomain.instance_serverless.first_or_initialize
end
def create
if PagesDomain.instance_serverless.count > 0
return redirect_to admin_serverless_domains_path, notice: _('An instance-level serverless domain already exists.')
end
@domain = PagesDomain.instance_serverless.create(create_params)
if @domain.persisted?
redirect_to admin_serverless_domains_path, notice: _('Domain was successfully created.')
else
render 'index'
end
end
def update
if domain.update(update_params)
redirect_to admin_serverless_domains_path, notice: _('Domain was successfully updated.')
else
render 'index'
end
end
def verify
result = VerifyPagesDomainService.new(domain).execute
if result[:status] == :success
flash[:notice] = _('Successfully verified domain ownership')
else
flash[:alert] = _('Failed to verify domain ownership')
end
redirect_to admin_serverless_domains_path
end
private
def domain
@domain = PagesDomain.instance_serverless.find(params[:id])
end
def check_feature_flag
render_404 unless Feature.enabled?(:serverless_domain)
end
def update_params
params.require(:pages_domain).permit(:user_provided_certificate, :user_provided_key)
end
def create_params
params.require(:pages_domain).permit(:domain, :user_provided_certificate, :user_provided_key)
end
end
......@@ -16,7 +16,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
push_frontend_feature_flag(:prometheus_computed_alerts)
end
before_action do
push_frontend_feature_flag(:auto_stop_environments)
push_frontend_feature_flag(:auto_stop_environments, default_enabled: true)
end
after_action :expire_etag_cache, only: [:cancel_auto_stop]
......
......@@ -18,7 +18,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
end
def diffs_batch
return render_404 unless Feature.enabled?(:diffs_batch_load, @merge_request.project)
return render_404 unless Feature.enabled?(:diffs_batch_load, @merge_request.project, default_enabled: true)
diffs = @compare.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options)
positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user)
......
......@@ -19,7 +19,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
before_action only: [:show] do
push_frontend_feature_flag(:diffs_batch_load, @project)
push_frontend_feature_flag(:diffs_batch_load, @project, default_enabled: true)
push_frontend_feature_flag(:single_mr_diff_view, @project)
push_frontend_feature_flag(:suggest_pipeline) if experiment_enabled?(:suggest_pipeline)
end
......
......@@ -14,6 +14,7 @@ class PagesDomain < ApplicationRecord
validates :domain, hostname: { allow_numeric_hostname: true }
validates :domain, uniqueness: { case_sensitive: false }
validates :certificate, :key, presence: true, if: :usage_serverless?
validates :certificate, presence: { message: 'must be present if HTTPS-only is enabled' },
if: :certificate_should_be_present?
validates :certificate, certificate: true, if: ->(domain) { domain.certificate.present? }
......@@ -64,6 +65,8 @@ class PagesDomain < ApplicationRecord
scope :with_logging_info, -> { includes(project: [:namespace, :route]) }
scope :instance_serverless, -> { where(wildcard: true, scope: :instance, usage: :serverless) }
def verified?
!!verified_at
end
......
......@@ -30,7 +30,7 @@ module Environments
def stop_in_batch
environments = Environment.auto_stoppable(BATCH_SIZE)
return false unless environments.exists? && Feature.enabled?(:auto_stop_environments)
return false unless environments.exists? && Feature.enabled?(:auto_stop_environments, default_enabled: true)
Ci::StopEnvironmentsService.execute_in_batch(environments)
end
......
......@@ -11,6 +11,7 @@ module Metrics
SEQUENCE = [
STAGES::CommonMetricsInserter,
STAGES::ProjectMetricsInserter,
STAGES::ProjectMetricsDetailsInserter,
STAGES::EndpointInserter,
STAGES::Sorter
].freeze
......
......@@ -24,8 +24,8 @@ module Snippets
spam_check(snippet, current_user)
snippet_saved = snippet.with_transaction_returning_status do
if snippet.save && snippet.store_mentions!
create_repository_for(snippet, current_user)
(snippet.save && snippet.store_mentions!).tap do |saved|
create_repository_for(snippet, current_user) if saved
end
end
......
- form_name = 'js-serverless-domain-settings'
- form_url = @domain.persisted? ? admin_serverless_domain_path(@domain.id, anchor: form_name) : admin_serverless_domains_path(anchor: form_name)
- show_certificate_card = @domain.persisted? && @domain.errors.blank?
= form_for @domain, url: form_url, html: { class: 'fieldset-form' } do |f|
= form_errors(@domain)
%fieldset
- if @domain.persisted?
- dns_record = "*.#{@domain.domain} CNAME #{Settings.pages.host}."
- verification_record = "#{@domain.verification_domain} TXT #{@domain.keyed_verification_code}"
.form-group.row
.col-sm-6.position-relative
= f.label :domain, _('Domain'), class: 'label-bold'
= f.text_field :domain, class: 'form-control has-floating-status-badge', readonly: true
.status-badge.floating-status-badge
- text, status = @domain.unverified? ? [_('Unverified'), 'badge-danger'] : [_('Verified'), 'badge-success']
.badge{ class: status }
= text
= link_to sprite_icon("redo"), verify_admin_serverless_domain_path(@domain.id), method: :post, class: "btn has-tooltip", title: _("Retry verification")
.col-sm-6
= f.label :serverless_domain_dns, _('DNS'), class: 'label-bold'
.input-group
= text_field_tag :serverless_domain_dns, dns_record , class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
= clipboard_button(target: '#serverless_domain_dns', class: 'btn-default input-group-text d-none d-sm-block')
.col-sm-12.form-text.text-muted
= _("To access this domain create a new DNS record")
.form-group
= f.label :serverless_domain_verification, _('Verification status'), class: 'label-bold'
.input-group
= text_field_tag :serverless_domain_verification, verification_record, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
= clipboard_button(target: '#serverless_domain_verification', class: 'btn-default d-none d-sm-block')
%p.form-text.text-muted
- link_to_help = link_to(_('verify ownership'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership'))
= _("To %{link_to_help} of your domain, add the above key to a TXT record within to your DNS configuration.").html_safe % { link_to_help: link_to_help }
- else
.form-group
= f.label :domain, _('Domain'), class: 'label-bold'
= f.text_field :domain, class: 'form-control'
- if show_certificate_card
.card.js-domain-cert-show
.card-header
= _('Certificate')
.d-flex.justify-content-between.align-items-center.p-3
%span
= @domain.subject || _('missing')
%button.btn.btn-remove.btn-sm.js-domain-cert-replace-btn{ type: 'button' }
= _('Replace')
.js-domain-cert-inputs{ class: ('hidden' if show_certificate_card) }
.form-group
= f.label :user_provided_certificate, _('Certificate (PEM)'), class: 'label-bold'
= f.text_area :user_provided_certificate, rows: 5, class: 'form-control', value: ''
%span.form-text.text-muted
= _("Upload a certificate for your domain with all intermediates")
.form-group
= f.label :user_provided_key, _('Key (PEM)'), class: 'label-bold'
= f.text_area :user_provided_key, rows: 5, class: 'form-control', value: ''
%span.form-text.text-muted
= _("Upload a private key for your certificate")
= f.submit @domain.persisted? ? _('Save changes') : _('Add domain'), class: "btn btn-success js-serverless-domain-submit", disabled: @domain.persisted?
- breadcrumb_title _("Operations")
- page_title _("Operations")
- @content_class = "limit-container-width" unless fluid_layout
-# normally expanded_by_default? is used here, but since this is the only panel
-# in this settings page, let's leave it always open by default
- expanded = true
%section.settings.as-serverless-domain.no-animate#js-serverless-domain-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Serverless domain')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _('Set an instance-wide domain that will be available to all clusters when installing Knative.')
.settings-content
- if Gitlab.config.pages.enabled
= render 'form'
- else
.card
.card-header
= s_('GitLabPages|Domains')
.nothing-here-block
= s_("GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it.")
......@@ -254,6 +254,11 @@
= link_to ci_cd_admin_application_settings_path, title: _('CI/CD') do
%span
= _('CI/CD')
- if Feature.enabled?(:serverless_domain)
= nav_link(path: 'application_settings#operations') do
= link_to admin_serverless_domains_path, title: _('Operations') do
%span
= _('Operations')
= nav_link(path: 'application_settings#reporting') do
= link_to reporting_admin_application_settings_path, title: _('Reporting') do
%span
......
......@@ -8,7 +8,7 @@ module Environments
feature_category :continuous_delivery
def perform
return unless Feature.enabled?(:auto_stop_environments)
return unless Feature.enabled?(:auto_stop_environments, default_enabled: true)
AutoStopService.new.execute
end
......
---
title: Adds path to edit custom metrics in dashboard response
merge_request: 24645
author:
type: added
---
title: Add admin settings panel for instance-level serverless domain (behind feature flag)
merge_request: 21222
author:
type: added
......@@ -10,7 +10,7 @@ Gitlab.ee do
end
# Needed to run migration
if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('licenses')
if Gitlab::Database.cached_table_exists?('licenses')
message = LicenseHelper.license_message(signed_in: true, is_admin: true, in_html: false)
if ::License.block_changes? && message.present?
warn "WARNING: #{message}"
......
......@@ -3,7 +3,7 @@
# We need to run this initializer after migrations are done so it doesn't fail on CI
Gitlab.ee do
if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('licenses')
if Gitlab::Database.cached_table_exists?('licenses')
if Gitlab::Database::LoadBalancing.enable?
Gitlab::Database.disable_prepared_statements
......
......@@ -32,6 +32,14 @@ namespace :admin do
resources :abuse_reports, only: [:index, :destroy]
resources :gitaly_servers, only: [:index]
namespace :serverless do
resources :domains, only: [:index, :create, :update] do
member do
post '/verify', to: 'domains#verify'
end
end
end
resources :spam_logs, only: [:index, :destroy] do
member do
post :mark_as_ham
......
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddTemporaryIndexToPromotionNotes < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :notes,
:note,
where: "noteable_type = 'Issue' AND system IS TRUE AND note LIKE 'promoted to epic%'",
name: 'tmp_idx_on_promoted_notes'
end
def down
# NO OP
end
end
# frozen_string_literal: true
class ScheduleFixOrphanPromotedIssues < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 100
BACKGROUND_MIGRATION = 'FixOrphanPromotedIssues'.freeze
disable_ddl_transaction!
class Note < ActiveRecord::Base
include EachBatch
self.table_name = 'notes'
scope :of_promotion, -> do
where(noteable_type: 'Issue')
.where('notes.system IS TRUE')
.where("notes.note LIKE 'promoted to epic%'")
end
end
def up
Note.of_promotion.each_batch(of: BATCH_SIZE) do |notes, index|
jobs = notes.map { |note| [BACKGROUND_MIGRATION, [note.id]] }
BackgroundMigrationWorker.bulk_perform_async(jobs)
end
end
def down
# NO OP
end
end
......@@ -2811,6 +2811,7 @@ ActiveRecord::Schema.define(version: 2020_02_13_220211) do
t.index ["id"], name: "epic_mentions_temp_index", where: "((note ~~ '%@%'::text) AND ((noteable_type)::text = 'Epic'::text))"
t.index ["line_code"], name: "index_notes_on_line_code"
t.index ["note"], name: "index_notes_on_note_trigram", opclass: :gin_trgm_ops, using: :gin
t.index ["note"], name: "tmp_idx_on_promoted_notes", where: "(((noteable_type)::text = 'Issue'::text) AND (system IS TRUE) AND (note ~~ 'promoted to epic%'::text))"
t.index ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type"
t.index ["project_id", "id"], name: "index_notes_on_project_id_and_id_and_system_false", where: "(NOT system)"
t.index ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type"
......
---
last_updated: 2019-09-16
---
# Audit Events **(STARTER)**
GitLab offers a way to view the changes made within the GitLab server for owners and administrators on a [paid plan][ee].
......
......@@ -584,6 +584,7 @@ a few things that you need to do:
1. Configure [object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
1. Configure [object storage for packages](../packages/index.md#using-object-storage) (optional feature).
1. Configure [object storage for dependency proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature).
1. Configure [object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
NOTE: **Note:**
One current feature of GitLab that still requires a shared directory (NFS) is
......
......@@ -18,7 +18,7 @@ GET /projects/:id/repository/commits
| `all` | boolean | no | Retrieve every commit from the repository |
| `with_stats` | boolean | no | Stats about each commit will be added to the response |
| `first_parent` | boolean | no | Follow only the first parent commit upon seeing a merge commit |
| `order` | string | no | List commits in order. Possible value: [`topo`](https://git-scm.com/docs/git-log#Documentation/git-log.txt---topo-order). |
| `order` | string | no | List commits in order. Possible values: `default`, [`topo`](https://git-scm.com/docs/git-log#Documentation/git-log.txt---topo-order). Defaults to `default`, the commits are shown in reverse chronological order. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits"
......
......@@ -624,6 +624,73 @@ to automatically stop.
You can read more in the [`.gitlab-ci.yml` reference](yaml/README.md#environmenton_stop).
#### Environments auto-stop
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/20956) in GitLab 12.8.
You can set a expiry time to environments and stop them automatically after a certain period.
For example, consider the use of this feature with Review Apps environments.
When you set up Review Apps, sometimes they keep running for a long time
because some merge requests are left as open. An example for this situation is when the author of the merge
request is not actively working on it, due to priority changes or a different approach was decided on, and the merge requests was simply forgotten.
Idle environments waste resources, therefore they
should be terminated as soon as possible.
To address this problem, you can specify an optional expiration date for
Review Apps environments. When the expiry time is reached, GitLab will automatically trigger a job
to stop the environment, eliminating the need of manually doing so. In case an environment is updated, the expiration is renewed
ensuring that only active merge requests keep running Review Apps.
To enable this feature, you need to specify the [`environment:auto_stop_in`](yaml/README.md#environmentauto_stop_in) keyword in `.gitlab-ci.yml`.
You can specify a human-friendly date as the value, such as `1 hour and 30 minutes` or `1 day`.
`auto_stop_in` uses the same format of [`artifacts:expire_in` docs](yaml/README.md#artifactsexpire_in).
##### Auto-stop example
In the following example, there is a basic review app setup that creates a new environment
per merge request. The `review_app` job is triggered by every push and
creates or updates an environment named `review/your-branch-name`.
The environment keeps running until `stop_review_app` is executed:
```yaml
review_app:
script: deploy-review-app
environment:
name: review/$CI_COMMIT_REF_NAME
on_stop: stop_review_app
auto_stop_in: 1 week
stop_review_app:
script: stop-review-app
environment:
name: review/$CI_COMMIT_REF_NAME
action: stop
when: manual
```
As long as a merge request is active and keeps getting new commits,
the review app will not stop, so developers don't need to worry about
re-initiating review app.
On the other hand, since `stop_review_app` is set to `auto_stop_in: 1 week`,
if a merge request becomes inactive for more than a week,
GitLab automatically triggers the `stop_review_app` job to stop the environment.
You can also check the expiration date of environments through the GitLab UI. To do so,
go to **Operations > Environments > Environment**. You can see the auto-stop period
at the left-top section and a pin-mark button at the right-top section. This pin-mark
button can be used to prevent auto-stopping the environment. By clicking this button, the `auto_stop_in` setting is over-written
and the environment will be active until it's stopped manually.
![Environment auto stop](img/environment_auto_stop_v12_8.png)
NOTE: **NOTE**
Due to the resource limitation, a background worker for stopping environments only
runs once every hour. This means environments will not be stopped at the exact
timestamp as the specified period, but will be stopped when the hourly cron worker
detects expired environments.
### Grouping similar environments
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7015) in GitLab 8.14.
......
......@@ -80,6 +80,11 @@ you can copy and paste into `.gitlab-ci.yml` as a starting point. To do so:
1. Feel free to tune this template to your own needs.
## Review Apps auto-stop
See how to [configure Review Apps environments to expire and auto-stop](../environments.md#environments-auto-stop)
after a given period of time.
## Review Apps examples
The following are example projects that demonstrate Review App configuration:
......
......@@ -105,7 +105,7 @@ The following table lists available parameters for jobs:
| [`tags`](#tags) | List of tags which are used to select Runner. |
| [`allow_failure`](#allow_failure) | Allow job to fail. Failed job doesn't contribute to commit status. |
| [`when`](#when) | When to run job. Also available: `when:manual` and `when:delayed`. |
| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, and `environment:action`. |
| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, `environment:auto_stop_in` and `environment:action`. |
| [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, and `cache:policy`. |
| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`, and `artifacts:reports:junit`.<br><br>In GitLab [Enterprise Edition](https://about.gitlab.com/pricing/), these are available: `artifacts:reports:codequality`, `artifacts:reports:sast`, `artifacts:reports:dependency_scanning`, `artifacts:reports:container_scanning`, `artifacts:reports:dast`, `artifacts:reports:license_management`, `artifacts:reports:performance` and `artifacts:reports:metrics`. |
| [`dependencies`](#dependencies) | Restrict which artifacts are passed to a specific job by providing a list of jobs to fetch artifacts from. |
......@@ -1453,6 +1453,29 @@ The `stop_review_app` job is **required** to have the following keywords defined
- `stage` should be the same as the `review_app` in order for the environment
to stop automatically when the branch is deleted
#### `environment:auto_stop_in`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/20956) in GitLab 12.8.
The `auto_stop_in` keyword is for specifying life period of the environment,
that when expired, GitLab GitLab automatically stops them.
For example,
```yaml
review_app:
script: deploy-review-app
environment:
name: review/$CI_COMMIT_REF_NAME
auto_stop_in: 1 day
```
When `review_app` job is executed and a review app is created, a life period of
the environment is set to `1 day`.
For more information, see
[the environments auto-stop documentation](../environments.md#environments-auto-stop)
#### `environment:kubernetes`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/27630) in GitLab 12.6.
......
......@@ -707,7 +707,7 @@ For more information about the available options, run:
### `#database-lab`
Another tool GitLab employees can use is a chatbot powered by [Joe](https://gitlab.com/postgres-ai/joe), available in the [`#database-lab`](https://gitlab.slack.com/archives/CLJMDRD8C) channel on Slack.
Another tool GitLab employees can use is a chatbot powered by [Joe](https://gitlab.com/postgres-ai/joe) which uses [Database Lab](https://gitlab.com/postgres-ai/database-lab) to instantly provide developers with their own clone of the production database. Joe is available in the [`#database-lab`](https://gitlab.slack.com/archives/CLJMDRD8C) channel on Slack.
Unlike chatops, it gives you a way to execute DDL statements (like creating indexes and tables) and get query plan not only for `SELECT` but also `UPDATE` and `DELETE`.
For example, in order to test new index you can do the following:
......@@ -742,6 +742,20 @@ For more information about the available options, run:
help
```
#### Tips & Tricks
The database connection is now maintained during your whole session, so you can use `exec set ...` for any session variables (such as `enable_seqscan` or `work_mem`). These settings will be applied to all subsequent commands until you reset them.
It is also possible to use transactions. This may be useful when you are working on statements that modify the data, for example INSERT, UPDATE, and DELETE. The `explain` command will perform `EXPLAIN ANALYZE`, which executes the statement. In order to run each `explain` starting from a clean state you can wrap it in a transaction, for example:
```sql
exec BEGIN
explain UPDATE some_table SET some_column = TRUE
exec ROLLBACK
```
## Further reading
A more extensive guide on understanding query plans can be found in
......
......@@ -488,6 +488,7 @@ Supported applications:
- [GitLab Runner](#install-gitlab-runner-using-gitlab-ci)
- [Cilium](#install-cilium-using-gitlab-ci)
- [JupyterHub](#install-jupyterhub-using-gitlab-ci)
- [Elastic Stack](#install-elastic-stack-using-gitlab-ci)
### Usage
......@@ -791,6 +792,33 @@ project. Refer to the
[chart reference](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference.html)
for the available configuration options.
### Install Elastic Stack using GitLab CI
> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/45) in GitLab 12.8.
Elastic Stack is installed using GitLab CI by defining configuration in
`.gitlab/managed-apps/config.yaml`.
The following configuration is required to install Elastic Stack using GitLab CI:
```yaml
elasticStack:
installed: true
```
Elastic Stack is installed into the `gitlab-managed-apps` namespace of your cluster.
You can check the default [values.yaml](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/elastic_stack/values.yaml) we set for this chart.
You can customize the installation of Elastic Stack by defining
`.gitlab/managed-apps/elastic-stack/values.yaml` file in your cluster
management project. Refer to the
[chart](https://github.com/helm/charts/blob/master/stable/elastic-stack/values.yaml) for the
available configuration options.
NOTE: **Note:**
In this alpha implementation of installing Elastic Stack through CI, reading the environment pod logs through Elasticsearch is unsupported. This is supported if [installed via the UI](#elastic-stack).
## Upgrading applications
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24789) in GitLab 11.8.
......
......@@ -38,7 +38,7 @@ module API
optional :all, type: Boolean, desc: 'Every commit will be returned'
optional :with_stats, type: Boolean, desc: 'Stats about each commit will be added to the response'
optional :first_parent, type: Boolean, desc: 'Only include the first parent of merges'
optional :order, type: String, desc: 'List commits in order', values: %w[topo]
optional :order, type: String, desc: 'List commits in order', default: 'default', values: %w[default topo]
use :pagination
end
get ':id/repository/commits' do
......
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# No OP for CE
class FixOrphanPromotedIssues
def perform(note_id)
end
end
end
end
Gitlab::BackgroundMigration::FixOrphanPromotedIssues.prepend_if_ee('EE::Gitlab::BackgroundMigration::FixOrphanPromotedIssues')
......@@ -233,7 +233,7 @@ module Gitlab
end
def self.cached_table_exists?(table_name)
connection.schema_cache.data_source_exists?(table_name)
exists? && connection.schema_cache.data_source_exists?(table_name)
end
def self.database_version
......
......@@ -324,7 +324,7 @@ module Gitlab
request.after = GitalyClient.timestamp(options[:after]) if options[:after]
request.before = GitalyClient.timestamp(options[:before]) if options[:before]
request.revision = encode_binary(options[:ref]) if options[:ref]
request.order = options[:order].upcase if options[:order].present?
request.order = options[:order].upcase.sub('DEFAULT', 'NONE') if options[:order].present?
request.paths = encode_repeated(Array(options[:path])) if options[:path].present?
......
......@@ -22,7 +22,7 @@ module Gitlab
def self.set_feature_cache
# During db:create and db:bootstrap skip feature query as DB is not available yet.
return false unless ActiveRecord::Base.connected? && Gitlab::Database.cached_table_exists?('features')
return false unless Gitlab::Database.cached_table_exists?('features')
self.enabled = Feature.enabled?(MARGINALIA_FEATURE_FLAG)
end
......
# frozen_string_literal: true
module Gitlab
module Metrics
module Dashboard
module Stages
class ProjectMetricsDetailsInserter < BaseStage
def transform!
dashboard[:panel_groups].each do |panel_group|
next unless panel_group
has_custom_metrics = custom_group_titles.include?(panel_group[:group])
panel_group[:has_custom_metrics] = has_custom_metrics
panel_group[:panels].each do |panel|
next unless panel
panel[:metrics].each do |metric|
next unless metric
metric[:edit_path] = has_custom_metrics ? edit_path(metric) : nil
end
end
end
end
private
def custom_group_titles
@custom_group_titles ||= PrometheusMetricEnums.custom_group_details.values.map { |group_details| group_details[:group_title] }
end
def edit_path(metric)
Gitlab::Routing.url_helpers.edit_project_prometheus_metric_path(project, metric[:metric_id])
end
end
end
end
end
end
......@@ -1107,6 +1107,9 @@ msgstr ""
msgid "Add comment now"
msgstr ""
msgid "Add domain"
msgstr ""
msgid "Add email address"
msgstr ""
......@@ -1919,6 +1922,9 @@ msgstr ""
msgid "An error occurred. Please try again."
msgstr ""
msgid "An instance-level serverless domain already exists."
msgstr ""
msgid "An issue can be a bug, a todo or a feature request that needs to be discussed in a project. Besides, issues are searchable and filterable."
msgstr ""
......@@ -6807,6 +6813,12 @@ msgstr ""
msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled"
msgstr ""
msgid "Domain was successfully created."
msgstr ""
msgid "Domain was successfully updated."
msgstr ""
msgid "Don't have an account yet?"
msgstr ""
......@@ -8184,6 +8196,9 @@ msgstr ""
msgid "Failed to upload object map file"
msgstr ""
msgid "Failed to verify domain ownership"
msgstr ""
msgid "Failure"
msgstr ""
......@@ -17229,6 +17244,9 @@ msgstr ""
msgid "Serverless"
msgstr ""
msgid "Serverless domain"
msgstr ""
msgid "ServerlessDetails|Function invocation metrics require Prometheus to be installed first."
msgstr ""
......@@ -17334,6 +17352,9 @@ msgstr ""
msgid "Set a template repository for projects in this group"
msgstr ""
msgid "Set an instance-wide domain that will be available to all clusters when installing Knative."
msgstr ""
msgid "Set default and restrict visibility levels. Configure import sources and git access protocol."
msgstr ""
......@@ -18548,6 +18569,9 @@ msgstr ""
msgid "Successfully unlocked"
msgstr ""
msgid "Successfully verified domain ownership"
msgstr ""
msgid "Suggest code changes which can be immediately applied in one click. Try it out!"
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Admin::Serverless::DomainsController do
let(:admin) { create(:admin) }
let(:user) { create(:user) }
describe '#index' do
context 'non-admin user' do
before do
sign_in(user)
end
it 'responds with 404' do
get :index
expect(response.status).to eq(404)
end
end
context 'admin user' do
before do
create(:pages_domain)
sign_in(admin)
end
context 'with serverless_domain feature disabled' do
before do
stub_feature_flags(serverless_domain: false)
end
it 'responds with 404' do
get :index
expect(response.status).to eq(404)
end
end
context 'when instance-level serverless domain exists' do
let!(:serverless_domain) { create(:pages_domain, :instance_serverless) }
it 'loads the instance serverless domain' do
get :index
expect(assigns(:domain).id).to eq(serverless_domain.id)
end
end
context 'when domain does not exist' do
it 'initializes an instance serverless domain' do
get :index
domain = assigns(:domain)
expect(domain.persisted?).to eq(false)
expect(domain.wildcard).to eq(true)
expect(domain.scope).to eq('instance')
expect(domain.usage).to eq('serverless')
end
end
end
end
describe '#create' do
let(:create_params) do
sample_domain = build(:pages_domain)
{
domain: 'serverless.gitlab.io',
user_provided_certificate: sample_domain.certificate,
user_provided_key: sample_domain.key
}
end
context 'non-admin user' do
before do
sign_in(user)
end
it 'responds with 404' do
post :create, params: { pages_domain: create_params }
expect(response.status).to eq(404)
end
end
context 'admin user' do
before do
sign_in(admin)
end
context 'with serverless_domain feature disabled' do
before do
stub_feature_flags(serverless_domain: false)
end
it 'responds with 404' do
post :create, params: { pages_domain: create_params }
expect(response.status).to eq(404)
end
end
context 'when an instance-level serverless domain exists' do
let!(:serverless_domain) { create(:pages_domain, :instance_serverless) }
it 'does not create a new domain' do
expect { post :create, params: { pages_domain: create_params } }.not_to change { PagesDomain.instance_serverless.count }
end
it 'redirects to index' do
post :create, params: { pages_domain: create_params }
expect(response).to redirect_to admin_serverless_domains_path
expect(flash[:notice]).to include('An instance-level serverless domain already exists.')
end
end
context 'when an instance-level serverless domain does not exist' do
it 'creates an instance serverless domain with the provided attributes' do
expect { post :create, params: { pages_domain: create_params } }.to change { PagesDomain.instance_serverless.count }.by(1)
domain = PagesDomain.instance_serverless.first
expect(domain.domain).to eq(create_params[:domain])
expect(domain.certificate).to eq(create_params[:user_provided_certificate])
expect(domain.key).to eq(create_params[:user_provided_key])
expect(domain.wildcard).to eq(true)
expect(domain.scope).to eq('instance')
expect(domain.usage).to eq('serverless')
end
it 'redirects to index' do
post :create, params: { pages_domain: create_params }
expect(response).to redirect_to admin_serverless_domains_path
expect(flash[:notice]).to include('Domain was successfully created.')
end
end
context 'when there are errors' do
it 'renders index view' do
post :create, params: { pages_domain: { foo: 'bar' } }
expect(assigns(:domain).errors.size).to be > 0
expect(response).to render_template('index')
end
end
end
end
describe '#update' do
let(:domain) { create(:pages_domain, :instance_serverless) }
let(:update_params) do
sample_domain = build(:pages_domain)
{
user_provided_certificate: sample_domain.certificate,
user_provided_key: sample_domain.key
}
end
context 'non-admin user' do
before do
sign_in(user)
end
it 'responds with 404' do
put :update, params: { id: domain.id, pages_domain: update_params }
expect(response.status).to eq(404)
end
end
context 'admin user' do
before do
sign_in(admin)
end
context 'with serverless_domain feature disabled' do
before do
stub_feature_flags(serverless_domain: false)
end
it 'responds with 404' do
put :update, params: { id: domain.id, pages_domain: update_params }
expect(response.status).to eq(404)
end
end
context 'when domain exists' do
it 'updates the domain with the provided attributes' do
new_certificate = build(:pages_domain, :ecdsa).certificate
new_key = build(:pages_domain, :ecdsa).key
put :update, params: { id: domain.id, pages_domain: { user_provided_certificate: new_certificate, user_provided_key: new_key } }
domain.reload
expect(domain.certificate).to eq(new_certificate)
expect(domain.key).to eq(new_key)
end
it 'does not update the domain name' do
put :update, params: { id: domain.id, pages_domain: { domain: 'new.com' } }
expect(domain.reload.domain).not_to eq('new.com')
end
it 'redirects to index' do
put :update, params: { id: domain.id, pages_domain: update_params }
expect(response).to redirect_to admin_serverless_domains_path
expect(flash[:notice]).to include('Domain was successfully updated.')
end
end
context 'when domain does not exist' do
it 'returns 404' do
put :update, params: { id: 0, pages_domain: update_params }
expect(response.status).to eq(404)
end
end
context 'when there are errors' do
it 'renders index view' do
put :update, params: { id: domain.id, pages_domain: { user_provided_certificate: 'bad certificate' } }
expect(assigns(:domain).errors.size).to be > 0
expect(response).to render_template('index')
end
end
end
end
describe '#verify' do
let(:domain) { create(:pages_domain, :instance_serverless) }
context 'non-admin user' do
before do
sign_in(user)
end
it 'responds with 404' do
post :verify, params: { id: domain.id }
expect(response.status).to eq(404)
end
end
context 'admin user' do
before do
sign_in(admin)
end
def stub_service
service = double(:service)
expect(VerifyPagesDomainService).to receive(:new).with(domain).and_return(service)
service
end
context 'with serverless_domain feature disabled' do
before do
stub_feature_flags(serverless_domain: false)
end
it 'responds with 404' do
post :verify, params: { id: domain.id }
expect(response.status).to eq(404)
end
end
it 'handles verification success' do
expect(stub_service).to receive(:execute).and_return(status: :success)
post :verify, params: { id: domain.id }
expect(response).to redirect_to admin_serverless_domains_path
expect(flash[:notice]).to eq('Successfully verified domain ownership')
end
it 'handles verification failure' do
expect(stub_service).to receive(:execute).and_return(status: :failed)
post :verify, params: { id: domain.id }
expect(response).to redirect_to admin_serverless_domains_path
expect(flash[:alert]).to eq('Failed to verify domain ownership')
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'Admin Serverless Domains', :js do
let(:sample_domain) { build(:pages_domain) }
before do
allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
sign_in(create(:admin))
end
it 'Add domain with certificate' do
visit admin_serverless_domains_path
fill_in 'pages_domain[domain]', with: 'foo.com'
fill_in 'pages_domain[user_provided_certificate]', with: sample_domain.certificate
fill_in 'pages_domain[user_provided_key]', with: sample_domain.key
click_button 'Add domain'
expect(current_path).to eq admin_serverless_domains_path
expect(page).to have_field('pages_domain[domain]', with: 'foo.com')
expect(page).to have_field('serverless_domain_dns', with: /^\*\.foo\.com CNAME /)
expect(page).to have_field('serverless_domain_verification', with: /^_gitlab-pages-verification-code.foo.com TXT /)
expect(page).not_to have_field('pages_domain[user_provided_certificate]')
expect(page).not_to have_field('pages_domain[user_provided_key]')
expect(page).to have_content 'Unverified'
expect(page).to have_content '/CN=test-certificate'
end
it 'Update domain certificate' do
visit admin_serverless_domains_path
fill_in 'pages_domain[domain]', with: 'foo.com'
fill_in 'pages_domain[user_provided_certificate]', with: sample_domain.certificate
fill_in 'pages_domain[user_provided_key]', with: sample_domain.key
click_button 'Add domain'
expect(current_path).to eq admin_serverless_domains_path
expect(page).not_to have_field('pages_domain[user_provided_certificate]')
expect(page).not_to have_field('pages_domain[user_provided_key]')
click_button 'Replace'
expect(page).to have_field('pages_domain[user_provided_certificate]')
expect(page).to have_field('pages_domain[user_provided_key]')
fill_in 'pages_domain[user_provided_certificate]', with: sample_domain.certificate
fill_in 'pages_domain[user_provided_key]', with: sample_domain.key
click_button 'Save changes'
expect(page).to have_content 'Domain was successfully updated'
expect(page).to have_content '/CN=test-certificate'
end
end
......@@ -16,7 +16,8 @@
"label": { "type": "string" },
"track": { "type": "string" },
"prometheus_endpoint_path": { "type": "string" },
"metric_id": { "type": "number" }
"metric_id": { "type": "number" },
"edit_path": { "type": ["string", "null"] }
},
"additionalProperties": false
}
......@@ -10,7 +10,8 @@
"panels": {
"type": "array",
"items": { "$ref": "panels.json" }
}
},
"has_custom_metrics": { "type": "boolean" }
},
"additionalProperties": false
}
......@@ -394,6 +394,12 @@ describe Gitlab::Database do
expect(described_class.cached_table_exists?(:bogus_table_name)).to be_falsey
end
end
it 'returns false when database does not exist' do
expect(ActiveRecord::Base).to receive(:connection) { raise ActiveRecord::NoDatabaseError, 'broken' }
expect(described_class.cached_table_exists?(:projects)).to be(false)
end
end
describe '.exists?' do
......
......@@ -281,6 +281,19 @@ describe Gitlab::GitalyClient::CommitService do
end
describe '#find_commits' do
it 'sends an RPC request with NONE when default' do
request = Gitaly::FindCommitsRequest.new(
repository: repository_message,
disable_walk: true,
order: 'NONE'
)
expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:find_commits)
.with(request, kind_of(Hash)).and_return([])
client.find_commits(order: 'default')
end
it 'sends an RPC request' do
request = Gitaly::FindCommitsRequest.new(
repository: repository_message,
......
......@@ -12,6 +12,7 @@ describe Gitlab::Metrics::Dashboard::Processor do
[
Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter,
Gitlab::Metrics::Dashboard::Stages::ProjectMetricsInserter,
Gitlab::Metrics::Dashboard::Stages::ProjectMetricsDetailsInserter,
Gitlab::Metrics::Dashboard::Stages::EndpointInserter,
Gitlab::Metrics::Dashboard::Stages::Sorter
]
......@@ -25,6 +26,10 @@ describe Gitlab::Metrics::Dashboard::Processor do
end
end
it 'includes boolean to indicate if panel group has custom metrics' do
expect(dashboard[:panel_groups]).to all(include( { has_custom_metrics: boolean } ))
end
context 'when the dashboard is not present' do
let(:dashboard_yml) { nil }
......@@ -145,7 +150,8 @@ describe Gitlab::Metrics::Dashboard::Processor do
unit: metric.unit,
label: metric.legend,
metric_id: metric.id,
prometheus_endpoint_path: prometheus_path(metric.query)
prometheus_endpoint_path: prometheus_path(metric.query),
edit_path: edit_metric_path(metric)
}
end
......@@ -165,4 +171,11 @@ describe Gitlab::Metrics::Dashboard::Processor do
identifier: metric
)
end
def edit_metric_path(metric)
Gitlab::Routing.url_helpers.edit_project_prometheus_metric_path(
project,
metric.id
)
end
end
......@@ -104,6 +104,14 @@ describe PagesDomain do
describe 'validate certificate' do
subject { domain }
context 'serverless domain' do
it 'requires certificate and key to be present' do
expect(build(:pages_domain, :without_certificate, :without_key, usage: :serverless)).not_to be_valid
expect(build(:pages_domain, :without_certificate, usage: :serverless)).not_to be_valid
expect(build(:pages_domain, :without_key, usage: :serverless)).not_to be_valid
end
end
context 'with matching key' do
let(:domain) { build(:pages_domain) }
......@@ -555,6 +563,28 @@ describe PagesDomain do
end
end
describe '.instance_serverless' do
subject { described_class.instance_serverless }
before do
create(:pages_domain, wildcard: true)
create(:pages_domain, :instance_serverless)
create(:pages_domain, scope: :instance)
create(:pages_domain, :instance_serverless)
create(:pages_domain, usage: :serverless)
end
it 'returns domains that are wildcard, instance-level, and serverless' do
expect(subject.length).to eq(2)
subject.each do |domain|
expect(domain.wildcard).to eq(true)
expect(domain.usage).to eq('serverless')
expect(domain.scope).to eq('instance')
end
end
end
describe '.need_auto_ssl_renewal' do
subject { described_class.need_auto_ssl_renewal }
......
......@@ -266,8 +266,30 @@ describe API::Commits do
end
end
context 'set to blank' do
let(:order) { '' }
context 'set to default' do
let(:order) { 'default' }
# git log --graph -n 6 --pretty=format:"%h" --date-order 0031876
# * 0031876
# |\
# * | bf6e164
# | * 48ca272
# * | 9d526f8
# | * 335bc94
# |/
# * 1039376
it 'returns project commits ordered by default order' do
commits = project.repository.commits("0031876", limit: 6, order: 'default')
get api(route, current_user)
expect(json_response.size).to eq(6)
expect(json_response.map { |entry| entry["id"] }).to eq(commits.map(&:id))
end
end
context 'set to an invalid parameter' do
let(:order) { 'invalid' }
it_behaves_like '400 response' do
let(:request) { get api(route, current_user) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Admin::Serverless::DomainsController do
it 'routes to #index' do
expect(get: '/admin/serverless/domains').to route_to('admin/serverless/domains#index')
end
it 'routes to #create' do
expect(post: '/admin/serverless/domains/').to route_to('admin/serverless/domains#create')
end
it 'routes to #update' do
expect(put: '/admin/serverless/domains/1').to route_to(controller: 'admin/serverless/domains', action: 'update', id: '1')
expect(patch: '/admin/serverless/domains/1').to route_to(controller: 'admin/serverless/domains', action: 'update', id: '1')
end
it 'routes #verify' do
expect(post: '/admin/serverless/domains/1/verify').to route_to(controller: 'admin/serverless/domains', action: 'verify', id: '1')
end
end
......@@ -164,7 +164,9 @@ describe Snippets::CreateService do
it 'does not create snippet repository' do
stub_feature_flags(version_snippets: false)
subject
expect do
subject
end.to change(Snippet, :count).by(1)
expect(snippet.repository_exists?).to be_falsey
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册