Commit b060b8b7 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 49a923c6
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
SEED_CYCLE_ANALYTICS: "true" SEED_CYCLE_ANALYTICS: "true"
SEED_PRODUCTIVITY_ANALYTICS: "true" SEED_PRODUCTIVITY_ANALYTICS: "true"
CYCLE_ANALYTICS_ISSUE_COUNT: 1 CYCLE_ANALYTICS_ISSUE_COUNT: 1
SIZE: 0 # number of external projects to fork, requires network connection SIZE: 0 # number of external projects to fork, requires network connection
# SEED_NESTED_GROUPS: "false" # requires network connection # SEED_NESTED_GROUPS: "false" # requires network connection
run-dev-fixtures: run-dev-fixtures:
......
...@@ -157,9 +157,9 @@ dast: ...@@ -157,9 +157,9 @@ dast:
extends: extends:
- .default-retry - .default-retry
- .reports:rules:dast - .reports:rules:dast
needs: # This is needed so that manual jobs with needs don't block the pipeline.
- job: review-deploy # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
artifacts: true dependencies: ["review-deploy"]
stage: qa # GitLab-specific stage: qa # GitLab-specific
image: image:
name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION" name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION"
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
build-qa-image: build-qa-image:
extends: extends:
- .review-docker - .review-docker
- .review:rules:mr-and-schedule - .review:rules:mr-and-schedule-auto
stage: prepare stage: prepare
script: script:
- '[[ ! -d "ee/" ]] || export GITLAB_EDITION="ee"' - '[[ ! -d "ee/" ]] || export GITLAB_EDITION="ee"'
...@@ -45,7 +45,7 @@ review-cleanup: ...@@ -45,7 +45,7 @@ review-cleanup:
review-build-cng: review-build-cng:
extends: extends:
- .default-retry - .default-retry
- .review:rules:mr-and-schedule - .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
image: ruby:2.6-alpine image: ruby:2.6-alpine
stage: review-prepare stage: review-prepare
before_script: before_script:
...@@ -57,6 +57,9 @@ review-build-cng: ...@@ -57,6 +57,9 @@ review-build-cng:
artifacts: false artifacts: false
script: script:
- BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng - BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng
# When the job is manual, review-deploy is also manual and we don't want people
# to have to manually start the jobs in sequence, so we do it for them.
- '[ -z $CI_JOB_MANUAL ] || play_job "review-deploy"'
.review-workflow-base: .review-workflow-base:
extends: extends:
...@@ -76,11 +79,9 @@ review-build-cng: ...@@ -76,11 +79,9 @@ review-build-cng:
review-deploy: review-deploy:
extends: extends:
- .review-workflow-base - .review-workflow-base
- .review:rules:mr-and-schedule - .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
stage: review stage: review
needs: dependencies: []
- job: review-build-cng
artifacts: false
resource_group: "review/${CI_COMMIT_REF_NAME}" resource_group: "review/${CI_COMMIT_REF_NAME}"
allow_failure: true allow_failure: true
before_script: before_script:
...@@ -100,6 +101,10 @@ review-deploy: ...@@ -100,6 +101,10 @@ review-deploy:
- download_chart - download_chart
- date - date
- deploy || (display_deployment_debug && exit 1) - deploy || (display_deployment_debug && exit 1)
# When the job is manual, review-qa-smoke is also manual and we don't want people
# to have to manually start the jobs in sequence, so we do it for them.
- '[ -z $CI_JOB_MANUAL ] || play_job "review-qa-smoke"'
- '[ -z $CI_JOB_MANUAL ] || play_job "review-performance"'
artifacts: artifacts:
paths: [environment_url.txt] paths: [environment_url.txt]
expire_in: 2 days expire_in: 2 days
...@@ -140,9 +145,9 @@ review-stop: ...@@ -140,9 +145,9 @@ review-stop:
.review-qa-base: .review-qa-base:
extends: .review-docker extends: .review-docker
stage: qa stage: qa
needs: # This is needed so that manual jobs with needs don't block the pipeline.
- job: review-deploy # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
artifacts: true dependencies: ["review-deploy"]
allow_failure: true allow_failure: true
variables: variables:
QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa" QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
...@@ -172,7 +177,7 @@ review-stop: ...@@ -172,7 +177,7 @@ review-stop:
review-qa-smoke: review-qa-smoke:
extends: extends:
- .review-qa-base - .review-qa-base
- .review:rules:mr-only-auto - .review:rules:mr-only-auto-if-frontend-manual-otherwise
script: script:
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" - gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
...@@ -189,11 +194,11 @@ review-qa-all: ...@@ -189,11 +194,11 @@ review-qa-all:
review-performance: review-performance:
extends: extends:
- .review-docker - .review-docker
- .review:rules:mr-and-schedule - .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
stage: qa stage: qa
needs: # This is needed so that manual jobs with needs don't block the pipeline.
- job: review-deploy # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
artifacts: true dependencies: ["review-deploy"]
allow_failure: true allow_failure: true
before_script: before_script:
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)" - export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
......
...@@ -57,6 +57,17 @@ ...@@ -57,6 +57,17 @@
- "doc/**/*" - "doc/**/*"
- ".markdownlint.json" - ".markdownlint.json"
.frontend-dependency-patterns: &frontend-dependency-patterns
- "{package.json,yarn.lock}"
.frontend-patterns: &frontend-patterns
- "{package.json,yarn.lock}"
- "{babel.config,jest.config}.js"
- ".csscomb.json"
- "Dockerfile.assets"
- "vendor/assets/**/*"
- "{,ee/}{app/assets,app/helpers,app/presenters,app/views,locale,public,symbol}/**/*"
.backstage-patterns: &backstage-patterns .backstage-patterns: &backstage-patterns
- "Dangerfile" - "Dangerfile"
- "danger/**/*" - "danger/**/*"
...@@ -66,39 +77,38 @@ ...@@ -66,39 +77,38 @@
- "doc/README.md" # Some RSpec test rely on this file - "doc/README.md" # Some RSpec test rely on this file
.code-patterns: &code-patterns .code-patterns: &code-patterns
- "{package.json,yarn.lock}"
- "{babel.config,jest.config}.js"
- ".csscomb.json"
- "Dockerfile.assets"
- "vendor/assets/**/*"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
- ".csscomb.json"
- "Dockerfile.assets"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
- "{babel.config,jest.config}.js"
- "config.ru" - "config.ru"
- "{package.json,yarn.lock}"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
.frontend-dependency-patterns: &frontend-dependency-patterns
- "{package.json,yarn.lock}"
.qa-patterns: &qa-patterns .qa-patterns: &qa-patterns
- ".dockerignore" - ".dockerignore"
- "qa/**/*" - "qa/**/*"
.code-backstage-patterns: &code-backstage-patterns .code-backstage-patterns: &code-backstage-patterns
- "{package.json,yarn.lock}"
- "{babel.config,jest.config}.js"
- ".csscomb.json"
- "Dockerfile.assets"
- "vendor/assets/**/*"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
- ".csscomb.json"
- "Dockerfile.assets"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
- "{babel.config,jest.config}.js"
- "config.ru" - "config.ru"
- "{package.json,yarn.lock}"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# Backstage changes # Backstage changes
...@@ -110,17 +120,18 @@ ...@@ -110,17 +120,18 @@
- "doc/README.md" # Some RSpec test rely on this file - "doc/README.md" # Some RSpec test rely on this file
.code-qa-patterns: &code-qa-patterns .code-qa-patterns: &code-qa-patterns
- "{package.json,yarn.lock}"
- "{babel.config,jest.config}.js"
- ".csscomb.json"
- "Dockerfile.assets"
- "vendor/assets/**/*"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
- ".csscomb.json"
- "Dockerfile.assets"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
- "{babel.config,jest.config}.js"
- "config.ru" - "config.ru"
- "{package.json,yarn.lock}"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# QA changes # QA changes
...@@ -128,17 +139,18 @@ ...@@ -128,17 +139,18 @@
- "qa/**/*" - "qa/**/*"
.code-backstage-qa-patterns: &code-backstage-qa-patterns .code-backstage-qa-patterns: &code-backstage-qa-patterns
- "{package.json,yarn.lock}"
- "{babel.config,jest.config}.js"
- ".csscomb.json"
- "Dockerfile.assets"
- "vendor/assets/**/*"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
- ".csscomb.json"
- "Dockerfile.assets"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
- "{babel.config,jest.config}.js"
- "config.ru" - "config.ru"
- "{package.json,yarn.lock}"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# Backstage changes # Backstage changes
...@@ -416,8 +428,12 @@ ...@@ -416,8 +428,12 @@
rules: rules:
- if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/' - if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/'
when: never when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-patterns
when: on_success
- <<: *if-dot-com-gitlab-org-merge-request - <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns changes: *code-qa-patterns
when: manual
.reports:schedule-dast: .reports:schedule-dast:
rules: rules:
...@@ -428,7 +444,7 @@ ...@@ -428,7 +444,7 @@
################ ################
# Review rules # # Review rules #
################ ################
.review:rules:mr-and-schedule: .review:rules:mr-and-schedule-auto:
rules: rules:
- <<: *if-dot-com-gitlab-org-merge-request - <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns changes: *code-qa-patterns
...@@ -436,12 +452,33 @@ ...@@ -436,12 +452,33 @@
- <<: *if-dot-com-gitlab-org-schedule - <<: *if-dot-com-gitlab-org-schedule
when: on_success when: on_success
.review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise:
rules:
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-patterns
when: on_success
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: manual
allow_failure: true
- <<: *if-dot-com-gitlab-org-schedule
when: on_success
.review:rules:mr-only-auto: .review:rules:mr-only-auto:
rules: rules:
- <<: *if-dot-com-gitlab-org-merge-request - <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns changes: *code-qa-patterns
when: on_success when: on_success
.review:rules:mr-only-auto-if-frontend-manual-otherwise:
rules:
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-patterns
when: on_success
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: manual
.review:rules:mr-only-manual: .review:rules:mr-only-manual:
rules: rules:
- <<: *if-dot-com-gitlab-org-merge-request - <<: *if-dot-com-gitlab-org-merge-request
......
...@@ -41,7 +41,7 @@ class Admin::ServicesController < Admin::ApplicationController ...@@ -41,7 +41,7 @@ class Admin::ServicesController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def service def service
@service ||= Service.where(id: params[:id], template: true).first @service ||= Service.find_by(id: params[:id], template: true)
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -4,7 +4,13 @@ module ImportUrlParams ...@@ -4,7 +4,13 @@ module ImportUrlParams
def import_url_params def import_url_params
return {} unless params.dig(:project, :import_url).present? return {} unless params.dig(:project, :import_url).present?
{ import_url: import_params_to_full_url(params[:project]) } {
import_url: import_params_to_full_url(params[:project]),
# We need to set import_type because attempting to retry an import by URL
# could leave a stale value around. This would erroneously cause an importer
# (e.g. import/export) to run.
import_type: 'git'
}
end end
def import_params_to_full_url(params) def import_params_to_full_url(params)
......
...@@ -55,6 +55,19 @@ module Emails ...@@ -55,6 +55,19 @@ module Emails
reply_to: @message.reply_to, reply_to: @message.reply_to,
subject: @message.subject) subject: @message.subject)
end end
def prometheus_alert_fired_email(project_id, user_id, alert_payload)
@project = ::Project.find(project_id)
user = ::User.find(user_id)
@alert = ::Gitlab::Alerting::Alert
.new(project: @project, payload: alert_payload)
.present
return unless @alert.valid?
subject_text = "Alert: #{@alert.full_title}"
mail(to: user.notification_email_for(@project.group), subject: subject(subject_text))
end
end end
end end
......
...@@ -523,6 +523,14 @@ class NotificationService ...@@ -523,6 +523,14 @@ class NotificationService
end end
end end
def prometheus_alerts_fired(project, alerts)
return if project.emails_disabled?
owners_and_maintainers_without_invites(project).to_a.product(alerts).each do |recipient, alert|
mailer.prometheus_alert_fired_email(project.id, recipient.user.id, alert).deliver_later
end
end
protected protected
def new_resource_email(target, method) def new_resource_email(target, method)
...@@ -618,6 +626,16 @@ class NotificationService ...@@ -618,6 +626,16 @@ class NotificationService
private private
def owners_and_maintainers_without_invites(project)
recipients = project.members.active_without_invites_and_requests.owners_and_maintainers
if recipients.empty? && project.group
recipients = project.group.members.active_without_invites_and_requests.owners_and_maintainers
end
recipients
end
def project_maintainers_recipients(target, action:) def project_maintainers_recipients(target, action:)
NotificationRecipients::BuildService.build_project_maintainers_recipients(target, action: action) NotificationRecipients::BuildService.build_project_maintainers_recipients(target, action: action)
end end
......
%p
= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project_full_path }
- if description = @alert.description
%p
= _('Description:')
= description
- if env_name = @alert.environment_name
%p
= _('Environment:')
= env_name
- if metric_query = @alert.metric_query
%p
= _('Metric:')
%pre
= metric_query
- if @alert.show_incident_issues_link?
%p
= link_to(_('View incident issues.'), @alert.incident_issues_link)
- if @alert.show_performance_dashboard_link?
%p
= link_to(_('View performance dashboard.'), @alert.performance_dashboard_link)
<%= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project_full_path } %>.
<% if description = @alert.description %>
<%= _('Description:') %> <%= description %>
<% end %>
<% if env_name = @alert.environment_name %>
<%= _('Environment:') %> <%= env_name %>
<% end %>
<% if metric_query = @alert.metric_query %>
<%= _('Metric:') %> <%= metric_query %>
<% end %>
<% if @alert.show_incident_issues_link? %>
<%= _('View incident issues.') %> <%= @alert.incident_issues_link %>
<% end %>
<% if @alert.show_performance_dashboard_link? %>
<%= _('View the performance dashboard at') %> <%= @alert.performance_dashboard_link %>
<% end %>
---
title: Ensure import by URL works after a failed import
merge_request: 27546
author:
type: fixed
# frozen_string_literal: true
class AddsSha256ToPackageFiles < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :packages_package_files, :file_sha256, :binary
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_03_16_111759) do ActiveRecord::Schema.define(version: 2020_03_18_152134) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm" enable_extension "pg_trgm"
...@@ -3057,6 +3057,7 @@ ActiveRecord::Schema.define(version: 2020_03_16_111759) do ...@@ -3057,6 +3057,7 @@ ActiveRecord::Schema.define(version: 2020_03_16_111759) do
t.binary "file_sha1" t.binary "file_sha1"
t.string "file_name", null: false t.string "file_name", null: false
t.text "file", null: false t.text "file", null: false
t.binary "file_sha256"
t.index ["package_id", "file_name"], name: "index_packages_package_files_on_package_id_and_file_name" t.index ["package_id", "file_name"], name: "index_packages_package_files_on_package_id_and_file_name"
end end
......
...@@ -133,7 +133,9 @@ and included in `rules` definitions via [YAML anchors](../ci/yaml/README.md#anch ...@@ -133,7 +133,9 @@ and included in `rules` definitions via [YAML anchors](../ci/yaml/README.md#anch
|------------------------------|--------------------------------------------------------------------------| |------------------------------|--------------------------------------------------------------------------|
| `yaml-patterns` | Only create job for YAML-related changes. | | `yaml-patterns` | Only create job for YAML-related changes. |
| `docs-patterns` | Only create job for docs-related changes. | | `docs-patterns` | Only create job for docs-related changes. |
| `backstage-patterns` | Only create job for backstage-related changes. | | `frontend-dependency-patterns` | Only create job when frontend dependencies are updated (i.e. `package.json`, and `yarn.lock`). changes. |
| `frontend-patterns` | Only create job for frontend-related changes. |
| `backstage-patterns` | Only create job for backstage-related changes (i.e. Danger, fixtures, RuboCop, specs). |
| `code-patterns` | Only create job for code-related changes. | | `code-patterns` | Only create job for code-related changes. |
| `qa-patterns` | Only create job for QA-related changes. | | `qa-patterns` | Only create job for QA-related changes. |
| `code-backstage-patterns` | Combination of `code-patterns` and `backstage-patterns`. | | `code-backstage-patterns` | Combination of `code-patterns` and `backstage-patterns`. |
......
...@@ -51,7 +51,7 @@ The Dashboard is the default view of the Admin Area, and is made up of the follo ...@@ -51,7 +51,7 @@ The Dashboard is the default view of the Admin Area, and is made up of the follo
| Section | Description | | Section | Description |
|:-----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------| |:-----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
| Projects | The total number of projects, up to 10 of the latest projects, and the option of creating a new project. | | Projects | The total number of projects, up to 10 of the latest projects, and the option of creating a new project. |
| Users | The total number of users, up to 10 of the latest users, and the option of creating a new user. | | Users | The total number of users, up to 10 of the latest users, the option of creating a new user, and a link to [**Users statistics**](#users-statistics). |
| Groups | The total number of groups, up to 10 of the latest groups, and the option of creating a new group. | | Groups | The total number of groups, up to 10 of the latest groups, and the option of creating a new group. |
| Statistics | Totals of all elements of the GitLab instance. | | Statistics | Totals of all elements of the GitLab instance. |
| Features | All features available on the GitLab instance. Enabled features are marked with a green circle icon, and disabled features are marked with a power icon. | | Features | All features available on the GitLab instance. Enabled features are marked with a green circle icon, and disabled features are marked with a power icon. |
...@@ -134,6 +134,19 @@ To search for users, enter your criteria in the search field. The user search is ...@@ -134,6 +134,19 @@ To search for users, enter your criteria in the search field. The user search is
insensitive, and applies partial matching to name and username. To search for an email address, insensitive, and applies partial matching to name and username. To search for an email address,
you must provide the complete email address. you must provide the complete email address.
#### Users statistics
The **Users statistics** page provides an overview of user accounts by role. Use this information
when validating seat usage of your subscription.
The page displays subtotals of all users matching criteria such as _Users with highest role
Maintainer_ and _Blocked users_.
The **Total users** is calculated as: **Active users** + **Blocked users**.
GitLab billing is based on the number of active users. For details of active users, see
[Choosing the number of users](../../subscriptions/index.md#choosing-the-number-of-users).
### Administering Groups ### Administering Groups
You can administer all groups in the GitLab instance from the Admin Area's Groups page. You can administer all groups in the GitLab instance from the Admin Area's Groups page.
......
...@@ -245,7 +245,7 @@ project): ...@@ -245,7 +245,7 @@ project):
```yaml ```yaml
include: include:
template: Serverless.gitlab-ci.yml - template: Serverless.gitlab-ci.yml
functions:build: functions:build:
extends: .serverless:build:functions extends: .serverless:build:functions
...@@ -462,7 +462,7 @@ Add the following `.gitlab-ci.yml` to the root of your repository ...@@ -462,7 +462,7 @@ Add the following `.gitlab-ci.yml` to the root of your repository
```yaml ```yaml
include: include:
template: Serverless.gitlab-ci.yml - template: Serverless.gitlab-ci.yml
build: build:
extends: .serverless:build:image extends: .serverless:build:image
......
...@@ -57,3 +57,54 @@ function echoinfo() { ...@@ -57,3 +57,54 @@ function echoinfo() {
printf "\033[0;33m%s\n\033[0m" "${1}" >&2; printf "\033[0;33m%s\n\033[0m" "${1}" >&2;
fi fi
} }
function get_job_id() {
local job_name="${1}"
local query_string="${2:+&${2}}"
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
local max_page=3
local page=1
while true; do
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs?per_page=100&page=${page}${query_string}"
echoinfo "GET ${url}"
local job_id
job_id=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq "map(select(.name == \"${job_name}\")) | map(.id) | last")
[[ "${job_id}" == "null" && "${page}" -lt "$max_page" ]] || break
let "page++"
done
if [[ "${job_id}" == "" ]]; then
echoerr "The '${job_name}' job ID couldn't be retrieved!"
else
echoinfo "The '${job_name}' job ID is ${job_id}"
echo "${job_id}"
fi
}
function play_job() {
local job_name="${1}"
local job_id
job_id=$(get_job_id "${job_name}" "scope=manual");
if [ -z "${job_id}" ]; then return; fi
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}/play"
echoinfo "POST ${url}"
local job_url
job_url=$(curl --silent --show-error --request POST --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".web_url")
echoinfo "Manual job '${job_name}' started at: ${job_url}"
}
...@@ -31,7 +31,8 @@ describe ImportUrlParams do ...@@ -31,7 +31,8 @@ describe ImportUrlParams do
describe '#import_url_params' do describe '#import_url_params' do
it 'returns hash with import_url' do it 'returns hash with import_url' do
expect(import_url_params).to eq( expect(import_url_params).to eq(
import_url: "https://user:password@url.com" import_url: "https://user:password@url.com",
import_type: 'git'
) )
end end
end end
...@@ -48,7 +49,8 @@ describe ImportUrlParams do ...@@ -48,7 +49,8 @@ describe ImportUrlParams do
describe '#import_url_params' do describe '#import_url_params' do
it 'does not change the url' do it 'does not change the url' do
expect(import_url_params).to eq( expect(import_url_params).to eq(
import_url: "https://user:password@url.com" import_url: "https://user:password@url.com",
import_type: 'git'
) )
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
require 'email_spec'
describe Emails::Projects do
include EmailSpec::Matchers
include_context 'gitlab email notification'
shared_examples 'no email' do
it 'does not send mail' do
expect(subject.message).to be_a_kind_of(ActionMailer::Base::NullMail)
end
end
shared_examples 'shows the incident issues url' do
context 'create issue setting enabled' do
before do
create(:project_incident_management_setting, project: project, create_issue: true)
end
let(:incident_issues_url) do
project_issues_url(project, label_name: 'incident')
end
it { is_expected.to have_body_text(incident_issues_url) }
end
end
let_it_be(:user) { create(:user) }
describe '#prometheus_alert_fired_email' do
subject do
Notify.prometheus_alert_fired_email(project.id, user.id, alert_params)
end
let(:alert_params) do
{ 'startsAt' => Time.now.rfc3339 }
end
context 'with a gitlab alert' do
before do
alert_params['labels'] = { 'gitlab_alert_id' => alert.prometheus_metric_id.to_s }
end
let(:title) do
"#{alert.title} #{alert.computed_operator} #{alert.threshold}"
end
let(:metrics_url) do
metrics_project_environment_url(project, environment)
end
let(:environment) { alert.environment }
let!(:alert) { create(:prometheus_alert, project: project) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{title} for 5 minutes")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
is_expected.to have_body_text('Environment:')
is_expected.to have_body_text(environment.name)
is_expected.to have_body_text('Metric:')
is_expected.to have_body_text(alert.full_query)
is_expected.to have_body_text(metrics_url)
end
it_behaves_like 'shows the incident issues url'
end
context 'with no payload' do
let(:alert_params) { {} }
it_behaves_like 'no email'
end
context 'with an unknown alert' do
before do
alert_params['labels'] = { 'gitlab_alert_id' => 'unknown' }
end
it_behaves_like 'no email'
end
context 'with an external alert' do
let(:title) { 'alert title' }
let(:metrics_url) do
metrics_project_environments_url(project)
end
before do
alert_params['annotations'] = { 'title' => title }
alert_params['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1'
end
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
is_expected.not_to have_body_text('Description:')
is_expected.not_to have_body_text('Environment:')
end
context 'with annotated description' do
let(:description) { 'description' }
before do
alert_params['annotations']['description'] = description
end
it 'shows the description' do
is_expected.to have_body_text('Description:')
is_expected.to have_body_text(description)
end
end
it_behaves_like 'shows the incident issues url'
end
end
end
...@@ -2783,6 +2783,41 @@ describe NotificationService, :mailer do ...@@ -2783,6 +2783,41 @@ describe NotificationService, :mailer do
end end
end end
describe '#prometheus_alerts_fired' do
let!(:project) { create(:project) }
let!(:prometheus_alert) { create(:prometheus_alert, project: project) }
let!(:master) { create(:user) }
let!(:developer) { create(:user) }
before do
project.add_master(master)
end
it 'sends the email to owners and masters' do
expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, prometheus_alert).and_call_original
expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, prometheus_alert).and_call_original
expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, prometheus_alert)
subject.prometheus_alerts_fired(prometheus_alert.project, [prometheus_alert])
end
it_behaves_like 'project emails are disabled' do
before do
allow_next_instance_of(::Gitlab::Alerting::Alert) do |instance|
allow(instance).to receive(:valid?).and_return(true)
end
end
let(:alert_params) { { 'labels' => { 'gitlab_alert_id' => 'unknown' } } }
let(:notification_target) { prometheus_alert.project }
let(:notification_trigger) { subject.prometheus_alerts_fired(prometheus_alert.project, [alert_params]) }
around do |example|
perform_enqueued_jobs { example.run }
end
end
end
def build_team(project) def build_team(project)
@u_watcher = create_global_setting_for(create(:user), :watch) @u_watcher = create_global_setting_for(create(:user), :watch)
@u_participating = create_global_setting_for(create(:user), :participating) @u_participating = create_global_setting_for(create(:user), :participating)
......
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