Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
49a923c646
commit
b060b8b7e4
20 changed files with 429 additions and 47 deletions
|
@ -157,9 +157,9 @@ dast:
|
|||
extends:
|
||||
- .default-retry
|
||||
- .reports:rules:dast
|
||||
needs:
|
||||
- job: review-deploy
|
||||
artifacts: true
|
||||
# This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
dependencies: ["review-deploy"]
|
||||
stage: qa # GitLab-specific
|
||||
image:
|
||||
name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
build-qa-image:
|
||||
extends:
|
||||
- .review-docker
|
||||
- .review:rules:mr-and-schedule
|
||||
- .review:rules:mr-and-schedule-auto
|
||||
stage: prepare
|
||||
script:
|
||||
- '[[ ! -d "ee/" ]] || export GITLAB_EDITION="ee"'
|
||||
|
@ -45,7 +45,7 @@ review-cleanup:
|
|||
review-build-cng:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .review:rules:mr-and-schedule
|
||||
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
image: ruby:2.6-alpine
|
||||
stage: review-prepare
|
||||
before_script:
|
||||
|
@ -57,6 +57,9 @@ review-build-cng:
|
|||
artifacts: false
|
||||
script:
|
||||
- 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:
|
||||
extends:
|
||||
|
@ -76,11 +79,9 @@ review-build-cng:
|
|||
review-deploy:
|
||||
extends:
|
||||
- .review-workflow-base
|
||||
- .review:rules:mr-and-schedule
|
||||
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
stage: review
|
||||
needs:
|
||||
- job: review-build-cng
|
||||
artifacts: false
|
||||
dependencies: []
|
||||
resource_group: "review/${CI_COMMIT_REF_NAME}"
|
||||
allow_failure: true
|
||||
before_script:
|
||||
|
@ -100,6 +101,10 @@ review-deploy:
|
|||
- download_chart
|
||||
- date
|
||||
- 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:
|
||||
paths: [environment_url.txt]
|
||||
expire_in: 2 days
|
||||
|
@ -140,9 +145,9 @@ review-stop:
|
|||
.review-qa-base:
|
||||
extends: .review-docker
|
||||
stage: qa
|
||||
needs:
|
||||
- job: review-deploy
|
||||
artifacts: true
|
||||
# This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
dependencies: ["review-deploy"]
|
||||
allow_failure: true
|
||||
variables:
|
||||
QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
|
||||
|
@ -172,7 +177,7 @@ review-stop:
|
|||
review-qa-smoke:
|
||||
extends:
|
||||
- .review-qa-base
|
||||
- .review:rules:mr-only-auto
|
||||
- .review:rules:mr-only-auto-if-frontend-manual-otherwise
|
||||
script:
|
||||
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
|
||||
|
||||
|
@ -189,11 +194,11 @@ review-qa-all:
|
|||
review-performance:
|
||||
extends:
|
||||
- .review-docker
|
||||
- .review:rules:mr-and-schedule
|
||||
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
stage: qa
|
||||
needs:
|
||||
- job: review-deploy
|
||||
artifacts: true
|
||||
# This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
dependencies: ["review-deploy"]
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
||||
|
|
|
@ -57,6 +57,17 @@
|
|||
- "doc/**/*"
|
||||
- ".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
|
||||
- "Dangerfile"
|
||||
- "danger/**/*"
|
||||
|
@ -66,39 +77,38 @@
|
|||
- "doc/README.md" # Some RSpec test rely on this file
|
||||
|
||||
.code-patterns: &code-patterns
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "vendor/assets/**/*"
|
||||
- ".gitlab/ci/**/*"
|
||||
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
|
||||
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- "config.ru"
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "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
|
||||
- ".dockerignore"
|
||||
- "qa/**/*"
|
||||
|
||||
.code-backstage-patterns: &code-backstage-patterns
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "vendor/assets/**/*"
|
||||
- ".gitlab/ci/**/*"
|
||||
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
|
||||
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- "config.ru"
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
# Backstage changes
|
||||
|
@ -110,17 +120,18 @@
|
|||
- "doc/README.md" # Some RSpec test rely on this file
|
||||
|
||||
.code-qa-patterns: &code-qa-patterns
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "vendor/assets/**/*"
|
||||
- ".gitlab/ci/**/*"
|
||||
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
|
||||
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- "config.ru"
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
# QA changes
|
||||
|
@ -128,17 +139,18 @@
|
|||
- "qa/**/*"
|
||||
|
||||
.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/**/*"
|
||||
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
|
||||
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
|
||||
- ".csscomb.json"
|
||||
- "Dockerfile.assets"
|
||||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "{babel.config,jest.config}.js"
|
||||
- "config.ru"
|
||||
- "{package.json,yarn.lock}"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
# Backstage changes
|
||||
|
@ -416,8 +428,12 @@
|
|||
rules:
|
||||
- if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/'
|
||||
when: never
|
||||
- <<: *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
|
||||
|
||||
.reports:schedule-dast:
|
||||
rules:
|
||||
|
@ -428,7 +444,7 @@
|
|||
################
|
||||
# Review rules #
|
||||
################
|
||||
.review:rules:mr-and-schedule:
|
||||
.review:rules:mr-and-schedule-auto:
|
||||
rules:
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *code-qa-patterns
|
||||
|
@ -436,12 +452,33 @@
|
|||
- <<: *if-dot-com-gitlab-org-schedule
|
||||
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:
|
||||
rules:
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *code-qa-patterns
|
||||
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:
|
||||
rules:
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
|
|
|
@ -41,7 +41,7 @@ class Admin::ServicesController < Admin::ApplicationController
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def service
|
||||
@service ||= Service.where(id: params[:id], template: true).first
|
||||
@service ||= Service.find_by(id: params[:id], template: true)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
@ -4,7 +4,13 @@ module ImportUrlParams
|
|||
def import_url_params
|
||||
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
|
||||
|
||||
def import_params_to_full_url(params)
|
||||
|
|
|
@ -55,6 +55,19 @@ module Emails
|
|||
reply_to: @message.reply_to,
|
||||
subject: @message.subject)
|
||||
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
|
||||
|
||||
|
|
|
@ -523,6 +523,14 @@ class NotificationService
|
|||
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
|
||||
|
||||
def new_resource_email(target, method)
|
||||
|
@ -618,6 +626,16 @@ class NotificationService
|
|||
|
||||
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:)
|
||||
NotificationRecipients::BuildService.build_project_maintainers_recipients(target, action: action)
|
||||
end
|
||||
|
|
28
app/views/notify/prometheus_alert_fired_email.html.haml
Normal file
28
app/views/notify/prometheus_alert_fired_email.html.haml
Normal file
|
@ -0,0 +1,28 @@
|
|||
%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)
|
||||
|
21
app/views/notify/prometheus_alert_fired_email.text.erb
Normal file
21
app/views/notify/prometheus_alert_fired_email.text.erb
Normal file
|
@ -0,0 +1,21 @@
|
|||
<%= _('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 %>
|
5
changelogs/unreleased/sh-fix-import-by-url-retries.yml
Normal file
5
changelogs/unreleased/sh-fix-import-by-url-retries.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Ensure import by URL works after a failed import
|
||||
merge_request: 27546
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,9 @@
|
|||
# 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 @@
|
|||
#
|
||||
# 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
|
||||
enable_extension "pg_trgm"
|
||||
|
@ -3057,6 +3057,7 @@ ActiveRecord::Schema.define(version: 2020_03_16_111759) do
|
|||
t.binary "file_sha1"
|
||||
t.string "file_name", 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"
|
||||
end
|
||||
|
||||
|
|
|
@ -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. |
|
||||
| `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. |
|
||||
| `qa-patterns` | Only create job for QA-related changes. |
|
||||
| `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
|
|||
| Section | Description |
|
||||
|:-----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 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. |
|
||||
| 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. |
|
||||
|
@ -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,
|
||||
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
|
||||
|
||||
You can administer all groups in the GitLab instance from the Admin Area's Groups page.
|
||||
|
|
|
@ -245,7 +245,7 @@ project):
|
|||
|
||||
```yaml
|
||||
include:
|
||||
template: Serverless.gitlab-ci.yml
|
||||
- template: Serverless.gitlab-ci.yml
|
||||
|
||||
functions:build:
|
||||
extends: .serverless:build:functions
|
||||
|
@ -462,7 +462,7 @@ Add the following `.gitlab-ci.yml` to the root of your repository
|
|||
|
||||
```yaml
|
||||
include:
|
||||
template: Serverless.gitlab-ci.yml
|
||||
- template: Serverless.gitlab-ci.yml
|
||||
|
||||
build:
|
||||
extends: .serverless:build:image
|
||||
|
|
|
@ -57,3 +57,54 @@ function echoinfo() {
|
|||
printf "\033[0;33m%s\n\033[0m" "${1}" >&2;
|
||||
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
|
|||
describe '#import_url_params' do
|
||||
it 'returns hash with import_url' do
|
||||
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
|
||||
|
@ -48,7 +49,8 @@ describe ImportUrlParams do
|
|||
describe '#import_url_params' do
|
||||
it 'does not change the url' do
|
||||
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
|
||||
|
|
136
spec/mailers/emails/projects_spec.rb
Normal file
136
spec/mailers/emails/projects_spec.rb
Normal file
|
@ -0,0 +1,136 @@
|
|||
# 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
|
|||
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)
|
||||
@u_watcher = create_global_setting_for(create(:user), :watch)
|
||||
@u_participating = create_global_setting_for(create(:user), :participating)
|
||||
|
|
Loading…
Reference in a new issue