Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a62238de73
commit
68c476dbd8
|
|
@ -9,8 +9,18 @@ build-qa-image:
|
|||
- .build-images:rules:build-qa-image
|
||||
stage: build-images
|
||||
needs: []
|
||||
variables:
|
||||
QA_IMAGE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
|
||||
script:
|
||||
- export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
|
||||
# With .git/hooks/post-checkout in place, Git tries to pull LFS objects, but the image doesn't have Git LFS, and we actually don't care about it for this specific so we just remove the file.
|
||||
# Without removing the file, the error is as follows: "This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-checkout."
|
||||
- rm .git/hooks/post-checkout
|
||||
# Use $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA so that GitLab image built in omnibus-gitlab-mirror and QA image are in sync.
|
||||
# This falls back to $CI_COMMIT_SHA (the default checked out commit) for the non-merged result pipelines.
|
||||
# See https://docs.gitlab.com/ee/development/testing_guide/end_to_end/index.html#with-pipeline-for-merged-results.
|
||||
- if [ -n "$CI_MERGE_REQUEST_SOURCE_BRANCH_SHA" ]; then
|
||||
git checkout -f ${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA};
|
||||
fi
|
||||
- /kaniko/executor --context=${CI_PROJECT_DIR} --dockerfile=${CI_PROJECT_DIR}/qa/Dockerfile --destination=${QA_IMAGE} --cache=true
|
||||
retry: 2
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@
|
|||
|
||||
.use-kaniko:
|
||||
image:
|
||||
name: gcr.io/kaniko-project/executor:debug-v1.3.0
|
||||
name: registry.gitlab.com/gitlab-org/gitlab-build-images:kaniko
|
||||
entrypoint: [""]
|
||||
before_script:
|
||||
- source scripts/utils.sh
|
||||
|
|
|
|||
|
|
@ -2941,7 +2941,6 @@ Style/RegexpLiteralMixedPreserve:
|
|||
- 'app/models/concerns/ci/maskable.rb'
|
||||
- 'app/models/operations/feature_flag.rb'
|
||||
- 'app/models/packages/go/module.rb'
|
||||
- 'app/models/project_services/chat_message/base_message.rb'
|
||||
- 'app/services/packages/conan/search_service.rb'
|
||||
- 'app/services/projects/update_remote_mirror_service.rb'
|
||||
- 'config/initializers/rspec_profiling.rb'
|
||||
|
|
|
|||
|
|
@ -598,7 +598,6 @@ Rails/RenderInline:
|
|||
# SupportedStyles: conservative, aggressive
|
||||
Rails/ShortI18n:
|
||||
Exclude:
|
||||
- 'app/models/project_services/chat_message/pipeline_message.rb'
|
||||
- 'app/uploaders/content_type_whitelist.rb'
|
||||
|
||||
# Offense count: 1144
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2be01682b4a0ba12cad12b30bad4dc8876503f22
|
||||
c93530dd0922e7554d6d1e486e830f72980fe083
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ export default {
|
|||
ghostClass: 'gl-visibility-hidden',
|
||||
},
|
||||
i18n: {
|
||||
dropzoneDescriptionText: __('Drop or %{linkStart}upload%{linkEnd} designs to attach'),
|
||||
dropzoneDescriptionText: __('Drag your designs here or %{linkStart}click to upload%{linkEnd}.'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ export default {
|
|||
GlTable,
|
||||
},
|
||||
inject: ['issuableId', 'issuableType'],
|
||||
props: {
|
||||
limitToHours: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return { report: [], isLoading: true };
|
||||
},
|
||||
|
|
@ -60,7 +67,10 @@ export default {
|
|||
},
|
||||
formatTimeSpent(seconds) {
|
||||
const negative = seconds < 0;
|
||||
return (negative ? '- ' : '') + stringifyTime(parseSeconds(seconds));
|
||||
return (
|
||||
(negative ? '- ' : '') +
|
||||
stringifyTime(parseSeconds(seconds, { limitToHours: this.limitToHours }))
|
||||
);
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ export default {
|
|||
:title="__('Time tracking report')"
|
||||
:hide-footer="true"
|
||||
>
|
||||
<time-tracking-report />
|
||||
<time-tracking-report :limit-to-hours="limitToHours" />
|
||||
</gl-modal>
|
||||
<transition name="help-state-toggle">
|
||||
<time-tracking-help-state v-if="showHelpState" />
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ export default {
|
|||
class="labels-fetch-loading gl-align-items-center w-100 h-100"
|
||||
size="md"
|
||||
/>
|
||||
<ul v-else class="list-unstyled mb-0">
|
||||
<ul v-else class="list-unstyled gl-mb-0 gl-word-break-word">
|
||||
<label-item
|
||||
v-for="(label, index) in visibleLabels"
|
||||
:key="label.id"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class DashboardController < Dashboard::ApplicationController
|
|||
|
||||
respond_to :html
|
||||
|
||||
feature_category :audit_events, [:activity]
|
||||
feature_category :users, [:activity]
|
||||
feature_category :issue_tracking, [:issues, :issues_calendar]
|
||||
feature_category :code_review, [:merge_requests]
|
||||
|
||||
|
|
|
|||
|
|
@ -49,10 +49,9 @@ class GroupsController < Groups::ApplicationController
|
|||
|
||||
feature_category :subgroups, [
|
||||
:index, :new, :create, :show, :edit, :update,
|
||||
:destroy, :details, :transfer
|
||||
:destroy, :details, :transfer, :activity
|
||||
]
|
||||
|
||||
feature_category :audit_events, [:activity]
|
||||
feature_category :issue_tracking, [:issues, :issues_calendar, :preview_markdown]
|
||||
feature_category :code_review, [:merge_requests, :unfoldered_environment_names]
|
||||
feature_category :projects, [:projects]
|
||||
|
|
|
|||
|
|
@ -43,13 +43,12 @@ class ProjectsController < Projects::ApplicationController
|
|||
|
||||
feature_category :projects, [
|
||||
:index, :show, :new, :create, :edit, :update, :transfer,
|
||||
:destroy, :resolve, :archive, :unarchive, :toggle_star
|
||||
:destroy, :resolve, :archive, :unarchive, :toggle_star, :activity
|
||||
]
|
||||
|
||||
feature_category :source_code_management, [:remove_fork, :housekeeping, :refs]
|
||||
feature_category :issue_tracking, [:preview_markdown, :new_issuable_address]
|
||||
feature_category :importers, [:export, :remove_export, :generate_new_export, :download_export]
|
||||
feature_category :audit_events, [:activity]
|
||||
feature_category :code_review, [:unfoldered_environment_names]
|
||||
|
||||
def index
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ module Packages
|
|||
.including_project_route
|
||||
.including_tags
|
||||
.for_projects(group_projects_visible_to_current_user.select(:id))
|
||||
.processed
|
||||
.sort_by_attribute("#{params[:order_by]}_#{params[:sort]}")
|
||||
|
||||
packages = filter_with_version(packages)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ module Packages
|
|||
def packages
|
||||
result = base.nuget
|
||||
.has_version
|
||||
.processed
|
||||
.with_name_like(@params[:package_name])
|
||||
result = result.with_version(@params[:package_version]) if @params[:package_version].present?
|
||||
result
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ module Packages
|
|||
.including_project_route
|
||||
.including_tags
|
||||
.displayable
|
||||
.processed
|
||||
.find(@package_id)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ module Packages
|
|||
.including_build_info
|
||||
.including_project_route
|
||||
.including_tags
|
||||
.processed
|
||||
packages = filter_with_version(packages)
|
||||
packages = filter_by_package_type(packages)
|
||||
packages = filter_by_package_name(packages)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module Packages
|
|||
private
|
||||
|
||||
def packages
|
||||
base.pypi.has_version.processed
|
||||
base.pypi.has_version
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module Packages
|
|||
private
|
||||
|
||||
def packages
|
||||
base.pypi.has_version.processed
|
||||
base.pypi.has_version
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class AlertMessage < BaseMessage
|
||||
attr_reader :title
|
||||
attr_reader :alert_url
|
||||
attr_reader :severity
|
||||
attr_reader :events
|
||||
attr_reader :status
|
||||
attr_reader :started_at
|
||||
|
||||
def initialize(params)
|
||||
@project_name = params[:project_name] || params.dig(:project, :path_with_namespace)
|
||||
@project_url = params.dig(:project, :web_url) || params[:project_url]
|
||||
@title = params.dig(:object_attributes, :title)
|
||||
@alert_url = params.dig(:object_attributes, :url)
|
||||
@severity = params.dig(:object_attributes, :severity)
|
||||
@events = params.dig(:object_attributes, :events)
|
||||
@status = params.dig(:object_attributes, :status)
|
||||
@started_at = params.dig(:object_attributes, :started_at)
|
||||
end
|
||||
|
||||
def attachments
|
||||
[{
|
||||
title: title,
|
||||
title_link: alert_url,
|
||||
color: attachment_color,
|
||||
fields: attachment_fields
|
||||
}]
|
||||
end
|
||||
|
||||
def message
|
||||
"Alert firing in #{project_name}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def attachment_color
|
||||
"#C95823"
|
||||
end
|
||||
|
||||
def attachment_fields
|
||||
[
|
||||
{
|
||||
title: "Severity",
|
||||
value: severity.to_s.humanize,
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Events",
|
||||
value: events,
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
value: status.to_s.humanize,
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Start time",
|
||||
value: format_time(started_at),
|
||||
short: true
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
# This formats time into the following format
|
||||
# April 23rd, 2020 1:06AM UTC
|
||||
def format_time(time)
|
||||
time = Time.zone.parse(time.to_s)
|
||||
time.strftime("%B #{time.day.ordinalize}, %Y %l:%M%p %Z")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class BaseMessage
|
||||
RELATIVE_LINK_REGEX = %r{!\[[^\]]*\]\((/uploads/[^\)]*)\)}.freeze
|
||||
|
||||
attr_reader :markdown
|
||||
attr_reader :user_full_name
|
||||
attr_reader :user_name
|
||||
attr_reader :user_avatar
|
||||
attr_reader :project_name
|
||||
attr_reader :project_url
|
||||
|
||||
def initialize(params)
|
||||
@markdown = params[:markdown] || false
|
||||
@project_name = params[:project_name] || params.dig(:project, :path_with_namespace)
|
||||
@project_url = params.dig(:project, :web_url) || params[:project_url]
|
||||
@user_full_name = params.dig(:user, :name) || params[:user_full_name]
|
||||
@user_name = params.dig(:user, :username) || params[:user_name]
|
||||
@user_avatar = params.dig(:user, :avatar_url) || params[:user_avatar]
|
||||
end
|
||||
|
||||
def user_combined_name
|
||||
if user_full_name.present?
|
||||
"#{user_full_name} (#{user_name})"
|
||||
else
|
||||
user_name
|
||||
end
|
||||
end
|
||||
|
||||
def summary
|
||||
return message if markdown
|
||||
|
||||
format(message)
|
||||
end
|
||||
|
||||
def pretext
|
||||
summary
|
||||
end
|
||||
|
||||
def fallback
|
||||
format(message)
|
||||
end
|
||||
|
||||
def attachments
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def activity
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def format(string)
|
||||
Slack::Messenger::Util::LinkFormatter.format(format_relative_links(string))
|
||||
end
|
||||
|
||||
def format_relative_links(string)
|
||||
string.gsub(RELATIVE_LINK_REGEX, "#{project_url}\\1")
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
'#345'
|
||||
end
|
||||
|
||||
def link(text, url)
|
||||
"[#{text}](#{url})"
|
||||
end
|
||||
|
||||
def pretty_duration(seconds)
|
||||
parse_string =
|
||||
if duration < 1.hour
|
||||
'%M:%S'
|
||||
else
|
||||
'%H:%M:%S'
|
||||
end
|
||||
|
||||
Time.at(seconds).utc.strftime(parse_string)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class DeploymentMessage < BaseMessage
|
||||
attr_reader :commit_title
|
||||
attr_reader :commit_url
|
||||
attr_reader :deployable_id
|
||||
attr_reader :deployable_url
|
||||
attr_reader :environment
|
||||
attr_reader :short_sha
|
||||
attr_reader :status
|
||||
attr_reader :user_url
|
||||
|
||||
def initialize(data)
|
||||
super
|
||||
|
||||
@commit_title = data[:commit_title]
|
||||
@commit_url = data[:commit_url]
|
||||
@deployable_id = data[:deployable_id]
|
||||
@deployable_url = data[:deployable_url]
|
||||
@environment = data[:environment]
|
||||
@short_sha = data[:short_sha]
|
||||
@status = data[:status]
|
||||
@user_url = data[:user_url]
|
||||
end
|
||||
|
||||
def attachments
|
||||
[{
|
||||
text: "#{project_link} with job #{deployment_link} by #{user_link}\n#{commit_link}: #{commit_title}",
|
||||
color: color
|
||||
}]
|
||||
end
|
||||
|
||||
def activity
|
||||
{}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
if running?
|
||||
"Starting deploy to #{environment}"
|
||||
else
|
||||
"Deploy to #{environment} #{humanized_status}"
|
||||
end
|
||||
end
|
||||
|
||||
def color
|
||||
case status
|
||||
when 'success'
|
||||
'good'
|
||||
when 'canceled'
|
||||
'warning'
|
||||
when 'failed'
|
||||
'danger'
|
||||
else
|
||||
'#334455'
|
||||
end
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
|
||||
def deployment_link
|
||||
link("##{deployable_id}", deployable_url)
|
||||
end
|
||||
|
||||
def user_link
|
||||
link(user_combined_name, user_url)
|
||||
end
|
||||
|
||||
def commit_link
|
||||
link(short_sha, commit_url)
|
||||
end
|
||||
|
||||
def humanized_status
|
||||
status == 'success' ? 'succeeded' : status
|
||||
end
|
||||
|
||||
def running?
|
||||
status == 'running'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class IssueMessage < BaseMessage
|
||||
attr_reader :title
|
||||
attr_reader :issue_iid
|
||||
attr_reader :issue_url
|
||||
attr_reader :action
|
||||
attr_reader :state
|
||||
attr_reader :description
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
obj_attr = params[:object_attributes]
|
||||
obj_attr = HashWithIndifferentAccess.new(obj_attr)
|
||||
@title = obj_attr[:title]
|
||||
@issue_iid = obj_attr[:iid]
|
||||
@issue_url = obj_attr[:url]
|
||||
@action = obj_attr[:action]
|
||||
@state = obj_attr[:state]
|
||||
@description = obj_attr[:description] || ''
|
||||
end
|
||||
|
||||
def attachments
|
||||
return [] unless opened_issue?
|
||||
return description if markdown
|
||||
|
||||
description_message
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "Issue #{state} by #{user_combined_name}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: issue_link,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"[#{project_link}] Issue #{issue_link} #{state} by #{user_combined_name}"
|
||||
end
|
||||
|
||||
def opened_issue?
|
||||
action == 'open'
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{
|
||||
title: issue_title,
|
||||
title_link: issue_url,
|
||||
text: format(description),
|
||||
color: '#C95823'
|
||||
}]
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
|
||||
def issue_link
|
||||
link(issue_title, issue_url)
|
||||
end
|
||||
|
||||
def issue_title
|
||||
"#{Issue.reference_prefix}#{issue_iid} #{title}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class MergeMessage < BaseMessage
|
||||
attr_reader :merge_request_iid
|
||||
attr_reader :source_branch
|
||||
attr_reader :target_branch
|
||||
attr_reader :action
|
||||
attr_reader :state
|
||||
attr_reader :title
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
obj_attr = params[:object_attributes]
|
||||
obj_attr = HashWithIndifferentAccess.new(obj_attr)
|
||||
@merge_request_iid = obj_attr[:iid]
|
||||
@source_branch = obj_attr[:source_branch]
|
||||
@target_branch = obj_attr[:target_branch]
|
||||
@action = obj_attr[:action]
|
||||
@state = obj_attr[:state]
|
||||
@title = format_title(obj_attr[:title])
|
||||
end
|
||||
|
||||
def attachments
|
||||
[]
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "Merge request #{state_or_action_text} by #{user_combined_name}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: merge_request_link,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_title(title)
|
||||
'*' + title.lines.first.chomp + '*'
|
||||
end
|
||||
|
||||
def message
|
||||
merge_request_message
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
|
||||
def merge_request_message
|
||||
"#{user_combined_name} #{state_or_action_text} merge request #{merge_request_link} in #{project_link}"
|
||||
end
|
||||
|
||||
def merge_request_link
|
||||
link(merge_request_title, merge_request_url)
|
||||
end
|
||||
|
||||
def merge_request_title
|
||||
"#{MergeRequest.reference_prefix}#{merge_request_iid} #{title}"
|
||||
end
|
||||
|
||||
def merge_request_url
|
||||
"#{project_url}/-/merge_requests/#{merge_request_iid}"
|
||||
end
|
||||
|
||||
def state_or_action_text
|
||||
case action
|
||||
when 'approved', 'unapproved'
|
||||
action
|
||||
when 'approval'
|
||||
'added their approval to'
|
||||
when 'unapproval'
|
||||
'removed their approval from'
|
||||
else
|
||||
state
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class NoteMessage < BaseMessage
|
||||
attr_reader :note
|
||||
attr_reader :note_url
|
||||
attr_reader :title
|
||||
attr_reader :target
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
params = HashWithIndifferentAccess.new(params)
|
||||
obj_attr = params[:object_attributes]
|
||||
@note = obj_attr[:note]
|
||||
@note_url = obj_attr[:url]
|
||||
@target, @title = case obj_attr[:noteable_type]
|
||||
when "Commit"
|
||||
create_commit_note(params[:commit])
|
||||
when "Issue"
|
||||
create_issue_note(params[:issue])
|
||||
when "MergeRequest"
|
||||
create_merge_note(params[:merge_request])
|
||||
when "Snippet"
|
||||
create_snippet_note(params[:snippet])
|
||||
end
|
||||
end
|
||||
|
||||
def attachments
|
||||
return note if markdown
|
||||
|
||||
description_message
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "#{user_combined_name} #{link('commented on ' + target, note_url)}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: formatted_title,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"#{user_combined_name} #{link('commented on ' + target, note_url)} in #{project_link}: *#{formatted_title}*"
|
||||
end
|
||||
|
||||
def format_title(title)
|
||||
title.lines.first.chomp
|
||||
end
|
||||
|
||||
def formatted_title
|
||||
format_title(title)
|
||||
end
|
||||
|
||||
def create_issue_note(issue)
|
||||
["issue #{Issue.reference_prefix}#{issue[:iid]}", issue[:title]]
|
||||
end
|
||||
|
||||
def create_commit_note(commit)
|
||||
commit_sha = Commit.truncate_sha(commit[:id])
|
||||
|
||||
["commit #{commit_sha}", commit[:message]]
|
||||
end
|
||||
|
||||
def create_merge_note(merge_request)
|
||||
["merge request #{MergeRequest.reference_prefix}#{merge_request[:iid]}", merge_request[:title]]
|
||||
end
|
||||
|
||||
def create_snippet_note(snippet)
|
||||
["snippet #{Snippet.reference_prefix}#{snippet[:id]}", snippet[:title]]
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{ text: format(note), color: attachment_color }]
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class PipelineMessage < BaseMessage
|
||||
MAX_VISIBLE_JOBS = 10
|
||||
|
||||
attr_reader :user
|
||||
attr_reader :ref_type
|
||||
attr_reader :ref
|
||||
attr_reader :status
|
||||
attr_reader :detailed_status
|
||||
attr_reader :duration
|
||||
attr_reader :finished_at
|
||||
attr_reader :pipeline_id
|
||||
attr_reader :failed_stages
|
||||
attr_reader :failed_jobs
|
||||
|
||||
attr_reader :project
|
||||
attr_reader :commit
|
||||
attr_reader :committer
|
||||
attr_reader :pipeline
|
||||
|
||||
def initialize(data)
|
||||
super
|
||||
|
||||
@user = data[:user]
|
||||
@user_name = data.dig(:user, :username) || 'API'
|
||||
|
||||
pipeline_attributes = data[:object_attributes]
|
||||
@ref_type = pipeline_attributes[:tag] ? 'tag' : 'branch'
|
||||
@ref = pipeline_attributes[:ref]
|
||||
@status = pipeline_attributes[:status]
|
||||
@detailed_status = pipeline_attributes[:detailed_status]
|
||||
@duration = pipeline_attributes[:duration].to_i
|
||||
@finished_at = pipeline_attributes[:finished_at] ? Time.parse(pipeline_attributes[:finished_at]).to_i : nil
|
||||
@pipeline_id = pipeline_attributes[:id]
|
||||
|
||||
# Get list of jobs that have actually failed (after exhausting all retries)
|
||||
@failed_jobs = actually_failed_jobs(Array(data[:builds]))
|
||||
@failed_stages = @failed_jobs.map { |j| j[:stage] }.uniq
|
||||
|
||||
@project = Project.find(data[:project][:id])
|
||||
@commit = project.commit_by(oid: data[:commit][:id])
|
||||
@committer = commit.committer
|
||||
@pipeline = Ci::Pipeline.find(pipeline_id)
|
||||
end
|
||||
|
||||
def pretext
|
||||
''
|
||||
end
|
||||
|
||||
def attachments
|
||||
return message if markdown
|
||||
|
||||
[{
|
||||
fallback: format(message),
|
||||
color: attachment_color,
|
||||
author_name: user_combined_name,
|
||||
author_icon: user_avatar,
|
||||
author_link: author_url,
|
||||
title: s_("ChatMessage|Pipeline #%{pipeline_id} %{humanized_status} in %{duration}") %
|
||||
{
|
||||
pipeline_id: pipeline_id,
|
||||
humanized_status: humanized_status,
|
||||
duration: pretty_duration(duration)
|
||||
},
|
||||
title_link: pipeline_url,
|
||||
fields: attachments_fields,
|
||||
footer: project.name,
|
||||
footer_icon: project.avatar_url(only_path: false),
|
||||
ts: finished_at
|
||||
}]
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: s_("ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status}") %
|
||||
{
|
||||
pipeline_link: pipeline_link,
|
||||
ref_type: ref_type,
|
||||
ref_link: ref_link,
|
||||
user_combined_name: user_combined_name,
|
||||
humanized_status: humanized_status
|
||||
},
|
||||
subtitle: s_("ChatMessage|in %{project_link}") % { project_link: project_link },
|
||||
text: s_("ChatMessage|in %{duration}") % { duration: pretty_duration(duration) },
|
||||
image: user_avatar || ''
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def actually_failed_jobs(builds)
|
||||
succeeded_job_names = builds.map { |b| b[:name] if b[:status] == 'success' }.compact.uniq
|
||||
|
||||
failed_jobs = builds.select do |build|
|
||||
# Select jobs which doesn't have a successful retry
|
||||
build[:status] == 'failed' && !succeeded_job_names.include?(build[:name])
|
||||
end
|
||||
|
||||
failed_jobs.uniq { |job| job[:name] }.reverse
|
||||
end
|
||||
|
||||
def failed_stages_field
|
||||
{
|
||||
title: s_("ChatMessage|Failed stage").pluralize(failed_stages.length),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(failed_stages_links),
|
||||
short: true
|
||||
}
|
||||
end
|
||||
|
||||
def failed_jobs_field
|
||||
{
|
||||
title: s_("ChatMessage|Failed job").pluralize(failed_jobs.length),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(failed_jobs_links),
|
||||
short: true
|
||||
}
|
||||
end
|
||||
|
||||
def yaml_error_field
|
||||
{
|
||||
title: s_("ChatMessage|Invalid CI config YAML file"),
|
||||
value: pipeline.yaml_errors,
|
||||
short: false
|
||||
}
|
||||
end
|
||||
|
||||
def attachments_fields
|
||||
fields = [
|
||||
{
|
||||
title: ref_type == "tag" ? s_("ChatMessage|Tag") : s_("ChatMessage|Branch"),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(ref_link),
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: s_("ChatMessage|Commit"),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(commit_link),
|
||||
short: true
|
||||
}
|
||||
]
|
||||
|
||||
fields << failed_stages_field if failed_stages.any?
|
||||
fields << failed_jobs_field if failed_jobs.any?
|
||||
fields << yaml_error_field if pipeline.has_yaml_errors?
|
||||
|
||||
fields
|
||||
end
|
||||
|
||||
def message
|
||||
s_("ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status} in %{duration}") %
|
||||
{
|
||||
project_link: project_link,
|
||||
pipeline_link: pipeline_link,
|
||||
ref_type: ref_type,
|
||||
ref_link: ref_link,
|
||||
user_combined_name: user_combined_name,
|
||||
humanized_status: humanized_status,
|
||||
duration: pretty_duration(duration)
|
||||
}
|
||||
end
|
||||
|
||||
def humanized_status
|
||||
case status
|
||||
when 'success'
|
||||
detailed_status == "passed with warnings" ? s_("ChatMessage|has passed with warnings") : s_("ChatMessage|has passed")
|
||||
when 'failed'
|
||||
s_("ChatMessage|has failed")
|
||||
else
|
||||
status
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
case status
|
||||
when 'success'
|
||||
detailed_status == 'passed with warnings' ? 'warning' : 'good'
|
||||
else
|
||||
'danger'
|
||||
end
|
||||
end
|
||||
|
||||
def ref_url
|
||||
if ref_type == 'tag'
|
||||
"#{project_url}/-/tags/#{ref}"
|
||||
else
|
||||
"#{project_url}/-/commits/#{ref}"
|
||||
end
|
||||
end
|
||||
|
||||
def ref_link
|
||||
"[#{ref}](#{ref_url})"
|
||||
end
|
||||
|
||||
def project_url
|
||||
project.web_url
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project.name}](#{project_url})"
|
||||
end
|
||||
|
||||
def pipeline_failed_jobs_url
|
||||
"#{project_url}/-/pipelines/#{pipeline_id}/failures"
|
||||
end
|
||||
|
||||
def pipeline_url
|
||||
if failed_jobs.any?
|
||||
pipeline_failed_jobs_url
|
||||
else
|
||||
"#{project_url}/-/pipelines/#{pipeline_id}"
|
||||
end
|
||||
end
|
||||
|
||||
def pipeline_link
|
||||
"[##{pipeline_id}](#{pipeline_url})"
|
||||
end
|
||||
|
||||
def job_url(job)
|
||||
"#{project_url}/-/jobs/#{job[:id]}"
|
||||
end
|
||||
|
||||
def job_link(job)
|
||||
"[#{job[:name]}](#{job_url(job)})"
|
||||
end
|
||||
|
||||
def failed_jobs_links
|
||||
failed = failed_jobs.slice(0, MAX_VISIBLE_JOBS)
|
||||
truncated = failed_jobs.slice(MAX_VISIBLE_JOBS, failed_jobs.size)
|
||||
|
||||
failed_links = failed.map { |job| job_link(job) }
|
||||
|
||||
unless truncated.blank?
|
||||
failed_links << s_("ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})") % {
|
||||
count: truncated.size,
|
||||
pipeline_failed_jobs_url: pipeline_failed_jobs_url
|
||||
}
|
||||
end
|
||||
|
||||
failed_links.join(I18n.t(:'support.array.words_connector'))
|
||||
end
|
||||
|
||||
def stage_link(stage)
|
||||
# All stages link to the pipeline page
|
||||
"[#{stage}](#{pipeline_url})"
|
||||
end
|
||||
|
||||
def failed_stages_links
|
||||
failed_stages.map { |s| stage_link(s) }.join(I18n.t(:'support.array.words_connector'))
|
||||
end
|
||||
|
||||
def commit_url
|
||||
Gitlab::UrlBuilder.build(commit)
|
||||
end
|
||||
|
||||
def commit_link
|
||||
"[#{commit.title}](#{commit_url})"
|
||||
end
|
||||
|
||||
def author_url
|
||||
return unless user && committer
|
||||
|
||||
Gitlab::UrlBuilder.build(committer)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class PushMessage < BaseMessage
|
||||
attr_reader :after
|
||||
attr_reader :before
|
||||
attr_reader :commits
|
||||
attr_reader :ref
|
||||
attr_reader :ref_type
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
@after = params[:after]
|
||||
@before = params[:before]
|
||||
@commits = params.fetch(:commits, [])
|
||||
@ref_type = Gitlab::Git.tag_ref?(params[:ref]) ? 'tag' : 'branch'
|
||||
@ref = Gitlab::Git.ref_name(params[:ref])
|
||||
end
|
||||
|
||||
def attachments
|
||||
return [] if new_branch? || removed_branch?
|
||||
return commit_messages if markdown
|
||||
|
||||
commit_message_attachments
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: humanized_action(short: true),
|
||||
subtitle: "in #{project_link}",
|
||||
text: compare_link,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def humanized_action(short: false)
|
||||
action, ref_link, target_link = compose_action_details
|
||||
text = [user_combined_name, action, ref_type, ref_link]
|
||||
text << target_link unless short
|
||||
text.join(' ')
|
||||
end
|
||||
|
||||
def message
|
||||
humanized_action
|
||||
end
|
||||
|
||||
def format(string)
|
||||
Slack::Messenger::Util::LinkFormatter.format(string)
|
||||
end
|
||||
|
||||
def commit_messages
|
||||
commits.map { |commit| compose_commit_message(commit) }.join("\n\n")
|
||||
end
|
||||
|
||||
def commit_message_attachments
|
||||
[{ text: format(commit_messages), color: attachment_color }]
|
||||
end
|
||||
|
||||
def compose_commit_message(commit)
|
||||
author = commit[:author][:name]
|
||||
id = Commit.truncate_sha(commit[:id])
|
||||
title = commit[:title]
|
||||
|
||||
url = commit[:url]
|
||||
|
||||
"[#{id}](#{url}): #{title} - #{author}"
|
||||
end
|
||||
|
||||
def new_branch?
|
||||
Gitlab::Git.blank_ref?(before)
|
||||
end
|
||||
|
||||
def removed_branch?
|
||||
Gitlab::Git.blank_ref?(after)
|
||||
end
|
||||
|
||||
def ref_url
|
||||
if ref_type == 'tag'
|
||||
"#{project_url}/-/tags/#{ref}"
|
||||
else
|
||||
"#{project_url}/commits/#{ref}"
|
||||
end
|
||||
end
|
||||
|
||||
def compare_url
|
||||
"#{project_url}/compare/#{before}...#{after}"
|
||||
end
|
||||
|
||||
def ref_link
|
||||
"[#{ref}](#{ref_url})"
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project_name}](#{project_url})"
|
||||
end
|
||||
|
||||
def compare_link
|
||||
"[Compare changes](#{compare_url})"
|
||||
end
|
||||
|
||||
def compose_action_details
|
||||
if new_branch?
|
||||
['pushed new', ref_link, "to #{project_link}"]
|
||||
elsif removed_branch?
|
||||
['removed', ref, "from #{project_link}"]
|
||||
else
|
||||
['pushed to', ref_link, "of #{project_link} (#{compare_link})"]
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
'#345'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module ChatMessage
|
||||
class WikiPageMessage < BaseMessage
|
||||
attr_reader :title
|
||||
attr_reader :wiki_page_url
|
||||
attr_reader :action
|
||||
attr_reader :description
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
obj_attr = params[:object_attributes]
|
||||
obj_attr = HashWithIndifferentAccess.new(obj_attr)
|
||||
@title = obj_attr[:title]
|
||||
@wiki_page_url = obj_attr[:url]
|
||||
@description = obj_attr[:message]
|
||||
|
||||
@action =
|
||||
case obj_attr[:action]
|
||||
when "create"
|
||||
"created"
|
||||
when "update"
|
||||
"edited"
|
||||
end
|
||||
end
|
||||
|
||||
def attachments
|
||||
return description if markdown
|
||||
|
||||
description_message
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "#{user_combined_name} #{action} #{wiki_page_link}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: title,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"#{user_combined_name} #{action} #{wiki_page_link} in #{project_link}: *#{title}*"
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{ text: format(@description), color: attachment_color }]
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project_name}](#{project_url})"
|
||||
end
|
||||
|
||||
def wiki_page_link
|
||||
"[wiki page](#{wiki_page_url})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -117,11 +117,6 @@ class Packages::Package < ApplicationRecord
|
|||
scope :without_nuget_temporary_name, -> { where.not(name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) }
|
||||
|
||||
scope :has_version, -> { where.not(version: nil) }
|
||||
scope :processed, -> do
|
||||
where.not(package_type: :nuget).or(
|
||||
where.not(name: Packages::Nuget::TEMPORARY_PACKAGE_NAME)
|
||||
)
|
||||
end
|
||||
scope :preload_files, -> { preload(:package_files) }
|
||||
scope :last_of_each_version, -> { where(id: all.select('MAX(id) AS id').group(:version)) }
|
||||
scope :limit_recent, ->(limit) { order_created_desc.limit(limit) }
|
||||
|
|
|
|||
|
|
@ -62,17 +62,16 @@ module Pages
|
|||
}
|
||||
end
|
||||
|
||||
# TODO: remove support for legacy storage in 14.3 https://gitlab.com/gitlab-org/gitlab/-/issues/328712
|
||||
# we support this till 14.3 to allow people to still use legacy storage if something goes very wrong
|
||||
# on self-hosted installations, and we'll need some time to fix it
|
||||
def legacy_source
|
||||
raise LegacyStorageDisabledError unless Feature.enabled?(:pages_serve_from_legacy_storage, default_enabled: true)
|
||||
return unless ::Settings.pages.local_store.enabled
|
||||
|
||||
{
|
||||
type: 'file',
|
||||
path: File.join(project.full_path, 'public/')
|
||||
}
|
||||
rescue LegacyStorageDisabledError => e
|
||||
Gitlab::ErrorTracking.track_exception(e, project_id: project.id)
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ module Pages
|
|||
project.pages_lookup_path(trim_prefix: trim_prefix, domain: domain)
|
||||
end
|
||||
|
||||
# TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/297524
|
||||
# source can only be nil if pages_serve_from_legacy_storage FF is disabled
|
||||
# we can remove this filtering once we remove legacy storage
|
||||
# TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/328715
|
||||
paths = paths.select(&:source)
|
||||
|
||||
paths.sort_by(&:prefix).reverse
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class AlertMessage < BaseMessage
|
||||
attr_reader :title
|
||||
attr_reader :alert_url
|
||||
attr_reader :severity
|
||||
attr_reader :events
|
||||
attr_reader :status
|
||||
attr_reader :started_at
|
||||
|
||||
def initialize(params)
|
||||
@project_name = params[:project_name] || params.dig(:project, :path_with_namespace)
|
||||
@project_url = params.dig(:project, :web_url) || params[:project_url]
|
||||
@title = params.dig(:object_attributes, :title)
|
||||
@alert_url = params.dig(:object_attributes, :url)
|
||||
@severity = params.dig(:object_attributes, :severity)
|
||||
@events = params.dig(:object_attributes, :events)
|
||||
@status = params.dig(:object_attributes, :status)
|
||||
@started_at = params.dig(:object_attributes, :started_at)
|
||||
end
|
||||
|
||||
def attachments
|
||||
[{
|
||||
title: title,
|
||||
title_link: alert_url,
|
||||
color: attachment_color,
|
||||
fields: attachment_fields
|
||||
}]
|
||||
end
|
||||
|
||||
def message
|
||||
"Alert firing in #{project_name}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def attachment_color
|
||||
"#C95823"
|
||||
end
|
||||
|
||||
def attachment_fields
|
||||
[
|
||||
{
|
||||
title: "Severity",
|
||||
value: severity.to_s.humanize,
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Events",
|
||||
value: events,
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
value: status.to_s.humanize,
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Start time",
|
||||
value: format_time(started_at),
|
||||
short: true
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
# This formats time into the following format
|
||||
# April 23rd, 2020 1:06AM UTC
|
||||
def format_time(time)
|
||||
time = Time.zone.parse(time.to_s)
|
||||
time.strftime("%B #{time.day.ordinalize}, %Y %l:%M%p %Z")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class BaseMessage
|
||||
RELATIVE_LINK_REGEX = /!\[[^\]]*\]\((\/uploads\/[^\)]*)\)/.freeze
|
||||
|
||||
attr_reader :markdown
|
||||
attr_reader :user_full_name
|
||||
attr_reader :user_name
|
||||
attr_reader :user_avatar
|
||||
attr_reader :project_name
|
||||
attr_reader :project_url
|
||||
|
||||
def initialize(params)
|
||||
@markdown = params[:markdown] || false
|
||||
@project_name = params[:project_name] || params.dig(:project, :path_with_namespace)
|
||||
@project_url = params.dig(:project, :web_url) || params[:project_url]
|
||||
@user_full_name = params.dig(:user, :name) || params[:user_full_name]
|
||||
@user_name = params.dig(:user, :username) || params[:user_name]
|
||||
@user_avatar = params.dig(:user, :avatar_url) || params[:user_avatar]
|
||||
end
|
||||
|
||||
def user_combined_name
|
||||
if user_full_name.present?
|
||||
"#{user_full_name} (#{user_name})"
|
||||
else
|
||||
user_name
|
||||
end
|
||||
end
|
||||
|
||||
def summary
|
||||
return message if markdown
|
||||
|
||||
format(message)
|
||||
end
|
||||
|
||||
def pretext
|
||||
summary
|
||||
end
|
||||
|
||||
def fallback
|
||||
format(message)
|
||||
end
|
||||
|
||||
def attachments
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def activity
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def format(string)
|
||||
Slack::Messenger::Util::LinkFormatter.format(format_relative_links(string))
|
||||
end
|
||||
|
||||
def format_relative_links(string)
|
||||
string.gsub(RELATIVE_LINK_REGEX, "#{project_url}\\1")
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
'#345'
|
||||
end
|
||||
|
||||
def link(text, url)
|
||||
"[#{text}](#{url})"
|
||||
end
|
||||
|
||||
def pretty_duration(seconds)
|
||||
parse_string =
|
||||
if duration < 1.hour
|
||||
'%M:%S'
|
||||
else
|
||||
'%H:%M:%S'
|
||||
end
|
||||
|
||||
Time.at(seconds).utc.strftime(parse_string)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class DeploymentMessage < BaseMessage
|
||||
attr_reader :commit_title
|
||||
attr_reader :commit_url
|
||||
attr_reader :deployable_id
|
||||
attr_reader :deployable_url
|
||||
attr_reader :environment
|
||||
attr_reader :short_sha
|
||||
attr_reader :status
|
||||
attr_reader :user_url
|
||||
|
||||
def initialize(data)
|
||||
super
|
||||
|
||||
@commit_title = data[:commit_title]
|
||||
@commit_url = data[:commit_url]
|
||||
@deployable_id = data[:deployable_id]
|
||||
@deployable_url = data[:deployable_url]
|
||||
@environment = data[:environment]
|
||||
@short_sha = data[:short_sha]
|
||||
@status = data[:status]
|
||||
@user_url = data[:user_url]
|
||||
end
|
||||
|
||||
def attachments
|
||||
[{
|
||||
text: "#{project_link} with job #{deployment_link} by #{user_link}\n#{commit_link}: #{commit_title}",
|
||||
color: color
|
||||
}]
|
||||
end
|
||||
|
||||
def activity
|
||||
{}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
if running?
|
||||
"Starting deploy to #{environment}"
|
||||
else
|
||||
"Deploy to #{environment} #{humanized_status}"
|
||||
end
|
||||
end
|
||||
|
||||
def color
|
||||
case status
|
||||
when 'success'
|
||||
'good'
|
||||
when 'canceled'
|
||||
'warning'
|
||||
when 'failed'
|
||||
'danger'
|
||||
else
|
||||
'#334455'
|
||||
end
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
|
||||
def deployment_link
|
||||
link("##{deployable_id}", deployable_url)
|
||||
end
|
||||
|
||||
def user_link
|
||||
link(user_combined_name, user_url)
|
||||
end
|
||||
|
||||
def commit_link
|
||||
link(short_sha, commit_url)
|
||||
end
|
||||
|
||||
def humanized_status
|
||||
status == 'success' ? 'succeeded' : status
|
||||
end
|
||||
|
||||
def running?
|
||||
status == 'running'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class IssueMessage < BaseMessage
|
||||
attr_reader :title
|
||||
attr_reader :issue_iid
|
||||
attr_reader :issue_url
|
||||
attr_reader :action
|
||||
attr_reader :state
|
||||
attr_reader :description
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
obj_attr = params[:object_attributes]
|
||||
obj_attr = HashWithIndifferentAccess.new(obj_attr)
|
||||
@title = obj_attr[:title]
|
||||
@issue_iid = obj_attr[:iid]
|
||||
@issue_url = obj_attr[:url]
|
||||
@action = obj_attr[:action]
|
||||
@state = obj_attr[:state]
|
||||
@description = obj_attr[:description] || ''
|
||||
end
|
||||
|
||||
def attachments
|
||||
return [] unless opened_issue?
|
||||
return description if markdown
|
||||
|
||||
description_message
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "Issue #{state} by #{user_combined_name}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: issue_link,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"[#{project_link}] Issue #{issue_link} #{state} by #{user_combined_name}"
|
||||
end
|
||||
|
||||
def opened_issue?
|
||||
action == 'open'
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{
|
||||
title: issue_title,
|
||||
title_link: issue_url,
|
||||
text: format(description),
|
||||
color: '#C95823'
|
||||
}]
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
|
||||
def issue_link
|
||||
link(issue_title, issue_url)
|
||||
end
|
||||
|
||||
def issue_title
|
||||
"#{Issue.reference_prefix}#{issue_iid} #{title}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class MergeMessage < BaseMessage
|
||||
attr_reader :merge_request_iid
|
||||
attr_reader :source_branch
|
||||
attr_reader :target_branch
|
||||
attr_reader :action
|
||||
attr_reader :state
|
||||
attr_reader :title
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
obj_attr = params[:object_attributes]
|
||||
obj_attr = HashWithIndifferentAccess.new(obj_attr)
|
||||
@merge_request_iid = obj_attr[:iid]
|
||||
@source_branch = obj_attr[:source_branch]
|
||||
@target_branch = obj_attr[:target_branch]
|
||||
@action = obj_attr[:action]
|
||||
@state = obj_attr[:state]
|
||||
@title = format_title(obj_attr[:title])
|
||||
end
|
||||
|
||||
def attachments
|
||||
[]
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "Merge request #{state_or_action_text} by #{user_combined_name}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: merge_request_link,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_title(title)
|
||||
'*' + title.lines.first.chomp + '*'
|
||||
end
|
||||
|
||||
def message
|
||||
merge_request_message
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
|
||||
def merge_request_message
|
||||
"#{user_combined_name} #{state_or_action_text} merge request #{merge_request_link} in #{project_link}"
|
||||
end
|
||||
|
||||
def merge_request_link
|
||||
link(merge_request_title, merge_request_url)
|
||||
end
|
||||
|
||||
def merge_request_title
|
||||
"#{MergeRequest.reference_prefix}#{merge_request_iid} #{title}"
|
||||
end
|
||||
|
||||
def merge_request_url
|
||||
"#{project_url}/-/merge_requests/#{merge_request_iid}"
|
||||
end
|
||||
|
||||
def state_or_action_text
|
||||
case action
|
||||
when 'approved', 'unapproved'
|
||||
action
|
||||
when 'approval'
|
||||
'added their approval to'
|
||||
when 'unapproval'
|
||||
'removed their approval from'
|
||||
else
|
||||
state
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class NoteMessage < BaseMessage
|
||||
attr_reader :note
|
||||
attr_reader :note_url
|
||||
attr_reader :title
|
||||
attr_reader :target
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
params = HashWithIndifferentAccess.new(params)
|
||||
obj_attr = params[:object_attributes]
|
||||
@note = obj_attr[:note]
|
||||
@note_url = obj_attr[:url]
|
||||
@target, @title = case obj_attr[:noteable_type]
|
||||
when "Commit"
|
||||
create_commit_note(params[:commit])
|
||||
when "Issue"
|
||||
create_issue_note(params[:issue])
|
||||
when "MergeRequest"
|
||||
create_merge_note(params[:merge_request])
|
||||
when "Snippet"
|
||||
create_snippet_note(params[:snippet])
|
||||
end
|
||||
end
|
||||
|
||||
def attachments
|
||||
return note if markdown
|
||||
|
||||
description_message
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "#{user_combined_name} #{link('commented on ' + target, note_url)}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: formatted_title,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"#{user_combined_name} #{link('commented on ' + target, note_url)} in #{project_link}: *#{formatted_title}*"
|
||||
end
|
||||
|
||||
def format_title(title)
|
||||
title.lines.first.chomp
|
||||
end
|
||||
|
||||
def formatted_title
|
||||
format_title(title)
|
||||
end
|
||||
|
||||
def create_issue_note(issue)
|
||||
["issue #{Issue.reference_prefix}#{issue[:iid]}", issue[:title]]
|
||||
end
|
||||
|
||||
def create_commit_note(commit)
|
||||
commit_sha = Commit.truncate_sha(commit[:id])
|
||||
|
||||
["commit #{commit_sha}", commit[:message]]
|
||||
end
|
||||
|
||||
def create_merge_note(merge_request)
|
||||
["merge request #{MergeRequest.reference_prefix}#{merge_request[:iid]}", merge_request[:title]]
|
||||
end
|
||||
|
||||
def create_snippet_note(snippet)
|
||||
["snippet #{Snippet.reference_prefix}#{snippet[:id]}", snippet[:title]]
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{ text: format(note), color: attachment_color }]
|
||||
end
|
||||
|
||||
def project_link
|
||||
link(project_name, project_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class PipelineMessage < BaseMessage
|
||||
MAX_VISIBLE_JOBS = 10
|
||||
|
||||
attr_reader :user
|
||||
attr_reader :ref_type
|
||||
attr_reader :ref
|
||||
attr_reader :status
|
||||
attr_reader :detailed_status
|
||||
attr_reader :duration
|
||||
attr_reader :finished_at
|
||||
attr_reader :pipeline_id
|
||||
attr_reader :failed_stages
|
||||
attr_reader :failed_jobs
|
||||
|
||||
attr_reader :project
|
||||
attr_reader :commit
|
||||
attr_reader :committer
|
||||
attr_reader :pipeline
|
||||
|
||||
def initialize(data)
|
||||
super
|
||||
|
||||
@user = data[:user]
|
||||
@user_name = data.dig(:user, :username) || 'API'
|
||||
|
||||
pipeline_attributes = data[:object_attributes]
|
||||
@ref_type = pipeline_attributes[:tag] ? 'tag' : 'branch'
|
||||
@ref = pipeline_attributes[:ref]
|
||||
@status = pipeline_attributes[:status]
|
||||
@detailed_status = pipeline_attributes[:detailed_status]
|
||||
@duration = pipeline_attributes[:duration].to_i
|
||||
@finished_at = pipeline_attributes[:finished_at] ? Time.parse(pipeline_attributes[:finished_at]).to_i : nil
|
||||
@pipeline_id = pipeline_attributes[:id]
|
||||
|
||||
# Get list of jobs that have actually failed (after exhausting all retries)
|
||||
@failed_jobs = actually_failed_jobs(Array(data[:builds]))
|
||||
@failed_stages = @failed_jobs.map { |j| j[:stage] }.uniq
|
||||
|
||||
@project = Project.find(data[:project][:id])
|
||||
@commit = project.commit_by(oid: data[:commit][:id])
|
||||
@committer = commit.committer
|
||||
@pipeline = Ci::Pipeline.find(pipeline_id)
|
||||
end
|
||||
|
||||
def pretext
|
||||
''
|
||||
end
|
||||
|
||||
def attachments
|
||||
return message if markdown
|
||||
|
||||
[{
|
||||
fallback: format(message),
|
||||
color: attachment_color,
|
||||
author_name: user_combined_name,
|
||||
author_icon: user_avatar,
|
||||
author_link: author_url,
|
||||
title: s_("ChatMessage|Pipeline #%{pipeline_id} %{humanized_status} in %{duration}") %
|
||||
{
|
||||
pipeline_id: pipeline_id,
|
||||
humanized_status: humanized_status,
|
||||
duration: pretty_duration(duration)
|
||||
},
|
||||
title_link: pipeline_url,
|
||||
fields: attachments_fields,
|
||||
footer: project.name,
|
||||
footer_icon: project.avatar_url(only_path: false),
|
||||
ts: finished_at
|
||||
}]
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: s_("ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status}") %
|
||||
{
|
||||
pipeline_link: pipeline_link,
|
||||
ref_type: ref_type,
|
||||
ref_link: ref_link,
|
||||
user_combined_name: user_combined_name,
|
||||
humanized_status: humanized_status
|
||||
},
|
||||
subtitle: s_("ChatMessage|in %{project_link}") % { project_link: project_link },
|
||||
text: s_("ChatMessage|in %{duration}") % { duration: pretty_duration(duration) },
|
||||
image: user_avatar || ''
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def actually_failed_jobs(builds)
|
||||
succeeded_job_names = builds.map { |b| b[:name] if b[:status] == 'success' }.compact.uniq
|
||||
|
||||
failed_jobs = builds.select do |build|
|
||||
# Select jobs which doesn't have a successful retry
|
||||
build[:status] == 'failed' && !succeeded_job_names.include?(build[:name])
|
||||
end
|
||||
|
||||
failed_jobs.uniq { |job| job[:name] }.reverse
|
||||
end
|
||||
|
||||
def failed_stages_field
|
||||
{
|
||||
title: s_("ChatMessage|Failed stage").pluralize(failed_stages.length),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(failed_stages_links),
|
||||
short: true
|
||||
}
|
||||
end
|
||||
|
||||
def failed_jobs_field
|
||||
{
|
||||
title: s_("ChatMessage|Failed job").pluralize(failed_jobs.length),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(failed_jobs_links),
|
||||
short: true
|
||||
}
|
||||
end
|
||||
|
||||
def yaml_error_field
|
||||
{
|
||||
title: s_("ChatMessage|Invalid CI config YAML file"),
|
||||
value: pipeline.yaml_errors,
|
||||
short: false
|
||||
}
|
||||
end
|
||||
|
||||
def attachments_fields
|
||||
fields = [
|
||||
{
|
||||
title: ref_type == "tag" ? s_("ChatMessage|Tag") : s_("ChatMessage|Branch"),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(ref_link),
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: s_("ChatMessage|Commit"),
|
||||
value: Slack::Messenger::Util::LinkFormatter.format(commit_link),
|
||||
short: true
|
||||
}
|
||||
]
|
||||
|
||||
fields << failed_stages_field if failed_stages.any?
|
||||
fields << failed_jobs_field if failed_jobs.any?
|
||||
fields << yaml_error_field if pipeline.has_yaml_errors?
|
||||
|
||||
fields
|
||||
end
|
||||
|
||||
def message
|
||||
s_("ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status} in %{duration}") %
|
||||
{
|
||||
project_link: project_link,
|
||||
pipeline_link: pipeline_link,
|
||||
ref_type: ref_type,
|
||||
ref_link: ref_link,
|
||||
user_combined_name: user_combined_name,
|
||||
humanized_status: humanized_status,
|
||||
duration: pretty_duration(duration)
|
||||
}
|
||||
end
|
||||
|
||||
def humanized_status
|
||||
case status
|
||||
when 'success'
|
||||
detailed_status == "passed with warnings" ? s_("ChatMessage|has passed with warnings") : s_("ChatMessage|has passed")
|
||||
when 'failed'
|
||||
s_("ChatMessage|has failed")
|
||||
else
|
||||
status
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
case status
|
||||
when 'success'
|
||||
detailed_status == 'passed with warnings' ? 'warning' : 'good'
|
||||
else
|
||||
'danger'
|
||||
end
|
||||
end
|
||||
|
||||
def ref_url
|
||||
if ref_type == 'tag'
|
||||
"#{project_url}/-/tags/#{ref}"
|
||||
else
|
||||
"#{project_url}/-/commits/#{ref}"
|
||||
end
|
||||
end
|
||||
|
||||
def ref_link
|
||||
"[#{ref}](#{ref_url})"
|
||||
end
|
||||
|
||||
def project_url
|
||||
project.web_url
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project.name}](#{project_url})"
|
||||
end
|
||||
|
||||
def pipeline_failed_jobs_url
|
||||
"#{project_url}/-/pipelines/#{pipeline_id}/failures"
|
||||
end
|
||||
|
||||
def pipeline_url
|
||||
if failed_jobs.any?
|
||||
pipeline_failed_jobs_url
|
||||
else
|
||||
"#{project_url}/-/pipelines/#{pipeline_id}"
|
||||
end
|
||||
end
|
||||
|
||||
def pipeline_link
|
||||
"[##{pipeline_id}](#{pipeline_url})"
|
||||
end
|
||||
|
||||
def job_url(job)
|
||||
"#{project_url}/-/jobs/#{job[:id]}"
|
||||
end
|
||||
|
||||
def job_link(job)
|
||||
"[#{job[:name]}](#{job_url(job)})"
|
||||
end
|
||||
|
||||
def failed_jobs_links
|
||||
failed = failed_jobs.slice(0, MAX_VISIBLE_JOBS)
|
||||
truncated = failed_jobs.slice(MAX_VISIBLE_JOBS, failed_jobs.size)
|
||||
|
||||
failed_links = failed.map { |job| job_link(job) }
|
||||
|
||||
unless truncated.blank?
|
||||
failed_links << s_("ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})") % {
|
||||
count: truncated.size,
|
||||
pipeline_failed_jobs_url: pipeline_failed_jobs_url
|
||||
}
|
||||
end
|
||||
|
||||
failed_links.join(I18n.translate(:'support.array.words_connector'))
|
||||
end
|
||||
|
||||
def stage_link(stage)
|
||||
# All stages link to the pipeline page
|
||||
"[#{stage}](#{pipeline_url})"
|
||||
end
|
||||
|
||||
def failed_stages_links
|
||||
failed_stages.map { |s| stage_link(s) }.join(I18n.translate(:'support.array.words_connector'))
|
||||
end
|
||||
|
||||
def commit_url
|
||||
Gitlab::UrlBuilder.build(commit)
|
||||
end
|
||||
|
||||
def commit_link
|
||||
"[#{commit.title}](#{commit_url})"
|
||||
end
|
||||
|
||||
def author_url
|
||||
return unless user && committer
|
||||
|
||||
Gitlab::UrlBuilder.build(committer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class PushMessage < BaseMessage
|
||||
attr_reader :after
|
||||
attr_reader :before
|
||||
attr_reader :commits
|
||||
attr_reader :ref
|
||||
attr_reader :ref_type
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
@after = params[:after]
|
||||
@before = params[:before]
|
||||
@commits = params.fetch(:commits, [])
|
||||
@ref_type = Gitlab::Git.tag_ref?(params[:ref]) ? 'tag' : 'branch'
|
||||
@ref = Gitlab::Git.ref_name(params[:ref])
|
||||
end
|
||||
|
||||
def attachments
|
||||
return [] if new_branch? || removed_branch?
|
||||
return commit_messages if markdown
|
||||
|
||||
commit_message_attachments
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: humanized_action(short: true),
|
||||
subtitle: "in #{project_link}",
|
||||
text: compare_link,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def humanized_action(short: false)
|
||||
action, ref_link, target_link = compose_action_details
|
||||
text = [user_combined_name, action, ref_type, ref_link]
|
||||
text << target_link unless short
|
||||
text.join(' ')
|
||||
end
|
||||
|
||||
def message
|
||||
humanized_action
|
||||
end
|
||||
|
||||
def format(string)
|
||||
Slack::Messenger::Util::LinkFormatter.format(string)
|
||||
end
|
||||
|
||||
def commit_messages
|
||||
commits.map { |commit| compose_commit_message(commit) }.join("\n\n")
|
||||
end
|
||||
|
||||
def commit_message_attachments
|
||||
[{ text: format(commit_messages), color: attachment_color }]
|
||||
end
|
||||
|
||||
def compose_commit_message(commit)
|
||||
author = commit[:author][:name]
|
||||
id = Commit.truncate_sha(commit[:id])
|
||||
title = commit[:title]
|
||||
|
||||
url = commit[:url]
|
||||
|
||||
"[#{id}](#{url}): #{title} - #{author}"
|
||||
end
|
||||
|
||||
def new_branch?
|
||||
Gitlab::Git.blank_ref?(before)
|
||||
end
|
||||
|
||||
def removed_branch?
|
||||
Gitlab::Git.blank_ref?(after)
|
||||
end
|
||||
|
||||
def ref_url
|
||||
if ref_type == 'tag'
|
||||
"#{project_url}/-/tags/#{ref}"
|
||||
else
|
||||
"#{project_url}/commits/#{ref}"
|
||||
end
|
||||
end
|
||||
|
||||
def compare_url
|
||||
"#{project_url}/compare/#{before}...#{after}"
|
||||
end
|
||||
|
||||
def ref_link
|
||||
"[#{ref}](#{ref_url})"
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project_name}](#{project_url})"
|
||||
end
|
||||
|
||||
def compare_link
|
||||
"[Compare changes](#{compare_url})"
|
||||
end
|
||||
|
||||
def compose_action_details
|
||||
if new_branch?
|
||||
['pushed new', ref_link, "to #{project_link}"]
|
||||
elsif removed_branch?
|
||||
['removed', ref, "from #{project_link}"]
|
||||
else
|
||||
['pushed to', ref_link, "of #{project_link} (#{compare_link})"]
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
'#345'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ChatMessage
|
||||
class WikiPageMessage < BaseMessage
|
||||
attr_reader :title
|
||||
attr_reader :wiki_page_url
|
||||
attr_reader :action
|
||||
attr_reader :description
|
||||
|
||||
def initialize(params)
|
||||
super
|
||||
|
||||
obj_attr = params[:object_attributes]
|
||||
obj_attr = HashWithIndifferentAccess.new(obj_attr)
|
||||
@title = obj_attr[:title]
|
||||
@wiki_page_url = obj_attr[:url]
|
||||
@description = obj_attr[:message]
|
||||
|
||||
@action =
|
||||
case obj_attr[:action]
|
||||
when "create"
|
||||
"created"
|
||||
when "update"
|
||||
"edited"
|
||||
end
|
||||
end
|
||||
|
||||
def attachments
|
||||
return description if markdown
|
||||
|
||||
description_message
|
||||
end
|
||||
|
||||
def activity
|
||||
{
|
||||
title: "#{user_combined_name} #{action} #{wiki_page_link}",
|
||||
subtitle: "in #{project_link}",
|
||||
text: title,
|
||||
image: user_avatar
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"#{user_combined_name} #{action} #{wiki_page_link} in #{project_link}: *#{title}*"
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{ text: format(@description), color: attachment_color }]
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project_name}](#{project_url})"
|
||||
end
|
||||
|
||||
def wiki_page_link
|
||||
"[wiki page](#{wiki_page_url})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -185,19 +185,19 @@ class ChatNotificationService < Integration
|
|||
def get_message(object_kind, data)
|
||||
case object_kind
|
||||
when "push", "tag_push"
|
||||
ChatMessage::PushMessage.new(data) if notify_for_ref?(data)
|
||||
Integrations::ChatMessage::PushMessage.new(data) if notify_for_ref?(data)
|
||||
when "issue"
|
||||
ChatMessage::IssueMessage.new(data) unless update?(data)
|
||||
Integrations::ChatMessage::IssueMessage.new(data) unless update?(data)
|
||||
when "merge_request"
|
||||
ChatMessage::MergeMessage.new(data) unless update?(data)
|
||||
Integrations::ChatMessage::MergeMessage.new(data) unless update?(data)
|
||||
when "note"
|
||||
ChatMessage::NoteMessage.new(data)
|
||||
Integrations::ChatMessage::NoteMessage.new(data)
|
||||
when "pipeline"
|
||||
ChatMessage::PipelineMessage.new(data) if should_pipeline_be_notified?(data)
|
||||
Integrations::ChatMessage::PipelineMessage.new(data) if should_pipeline_be_notified?(data)
|
||||
when "wiki_page"
|
||||
ChatMessage::WikiPageMessage.new(data)
|
||||
Integrations::ChatMessage::WikiPageMessage.new(data)
|
||||
when "deployment"
|
||||
ChatMessage::DeploymentMessage.new(data)
|
||||
Integrations::ChatMessage::DeploymentMessage.new(data)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class SlackService < ChatNotificationService
|
|||
end
|
||||
|
||||
def get_message(object_kind, data)
|
||||
return ChatMessage::AlertMessage.new(data) if object_kind == 'alert'
|
||||
return Integrations::ChatMessage::AlertMessage.new(data) if object_kind == 'alert'
|
||||
|
||||
super
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,25 +26,13 @@ module Issuable
|
|||
end
|
||||
|
||||
def delete_todos(actor, issuable)
|
||||
if Feature.enabled?(:destroy_issuable_todos_async, actor, default_enabled: :yaml)
|
||||
TodosDestroyer::DestroyedIssuableWorker
|
||||
.perform_async(issuable.id, issuable.class.name)
|
||||
else
|
||||
TodosDestroyer::DestroyedIssuableWorker
|
||||
.new
|
||||
.perform(issuable.id, issuable.class.name)
|
||||
end
|
||||
TodosDestroyer::DestroyedIssuableWorker
|
||||
.perform_async(issuable.id, issuable.class.name)
|
||||
end
|
||||
|
||||
def delete_label_links(actor, issuable)
|
||||
if Feature.enabled?(:destroy_issuable_label_links_async, actor, default_enabled: :yaml)
|
||||
Issuable::LabelLinksDestroyWorker
|
||||
.perform_async(issuable.id, issuable.class.name)
|
||||
else
|
||||
Issuable::LabelLinksDestroyWorker
|
||||
.new
|
||||
.perform(issuable.id, issuable.class.name)
|
||||
end
|
||||
Issuable::LabelLinksDestroyWorker
|
||||
.perform_async(issuable.id, issuable.class.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,12 +16,17 @@ module Spam
|
|||
def execute
|
||||
spamcheck_result = nil
|
||||
spamcheck_attribs = {}
|
||||
spamcheck_error = false
|
||||
|
||||
external_spam_check_round_trip_time = Benchmark.realtime do
|
||||
spamcheck_result, spamcheck_attribs = spamcheck_verdict
|
||||
spamcheck_result, spamcheck_attribs, spamcheck_error = spamcheck_verdict
|
||||
end
|
||||
|
||||
# assign result to a var and log it before reassigning to nil when monitorMode is true
|
||||
label = spamcheck_error ? 'ERROR' : spamcheck_result.to_s.upcase
|
||||
|
||||
histogram.observe( { result: label }, external_spam_check_round_trip_time )
|
||||
|
||||
# assign result to a var for logging it before reassigning to nil when monitorMode is true
|
||||
original_spamcheck_result = spamcheck_result
|
||||
|
||||
spamcheck_result = nil if spamcheck_attribs&.fetch("monitorMode", "false") == "true"
|
||||
|
|
@ -83,8 +88,9 @@ module Spam
|
|||
end
|
||||
rescue StandardError => e
|
||||
Gitlab::ErrorTracking.log_exception(e)
|
||||
|
||||
# Default to ALLOW if any errors occur
|
||||
[ALLOW, attribs]
|
||||
[ALLOW, attribs, true]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -95,5 +101,9 @@ module Spam
|
|||
def logger
|
||||
@logger ||= Gitlab::AppJsonLogger.build
|
||||
end
|
||||
|
||||
def histogram
|
||||
@histogram ||= Gitlab::Metrics.histogram(:gitlab_spamcheck_request_duration_seconds, 'Request duration to the anti-spam service')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
%p
|
||||
= _('%{username} changed the draft status of merge request %{mr_reference}' % {username: sanitize_name(@updated_by_user.name), mr_reference: @merge_request.to_reference })
|
||||
%p= html_escape(_('%{username} changed the draft status of merge request %{mr_link}')) % { username: link_to(@updated_by_user.name, user_url(@updated_by_user)),
|
||||
mr_link: merge_request_reference_link(@merge_request) }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count
|
||||
|
||||
- if issuable_mr > 0
|
||||
%li.issuable-mr.gl-display-none.gl-sm-display-block.has-tooltip{ title: _('Related merge requests') }
|
||||
%li.issuable-mr.gl-display-none.gl-sm-display-block.has-tooltip{ title: _('Related merge requests'), data: { testid: 'merge-requests' } }
|
||||
= sprite_icon('merge-request', css_class: "gl-vertical-align-middle")
|
||||
= issuable_mr
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Change wording for design management upload
|
||||
merge_request: 61782
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove pages_update_legacy_storage feature flag
|
||||
merge_request: 60005
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove pages_serve_from_legacy_storage feature flag
|
||||
merge_request: 60010
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove issuable destroy service related FFs
|
||||
merge_request: 61764
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Prepare devops adoption database structure for migration
|
||||
merge_request: 60733
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Observe limit to hours setting in timelog report
|
||||
merge_request: 61849
|
||||
author: Lee Tickett @leetickett
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add duplicated gin trigram index on notes table (note) to replace existing
|
||||
merge_request: 61430
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add link to email notifying of MR changing draft status
|
||||
merge_request: 61891
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Apply rate-limit cache to branches endpoint
|
||||
merge_request: 61723
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Send in-product marketing email usage data
|
||||
merge_request: 56752
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/330876
|
|||
milestone: '13.12'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: destroy_issuable_label_links_async
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60487
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/325689
|
||||
milestone: '13.12'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: destroy_issuable_todos_async
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57830
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/325689
|
||||
milestone: '13.11'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: pages_serve_from_legacy_storage
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/297228
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/297524
|
||||
milestone: '13.8'
|
||||
type: development
|
||||
group: group::release
|
||||
default_enabled: true
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: pages_update_legacy_storage
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50683
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296138
|
||||
milestone: '13.9'
|
||||
type: development
|
||||
group: group::release
|
||||
default_enabled: true
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_create_0_sent
|
||||
name: "count_sent_first_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the create track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_create_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the create track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_create_1_sent
|
||||
name: "count_sent_second_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the create track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_create_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the create track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_create_2_sent
|
||||
name: "count_sent_third_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the create track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_create_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_create_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the create track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_verify_0_sent
|
||||
name: "count_sent_first_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the verify track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_verify_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_verify_1_sent
|
||||
name: "count_sent_second_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the verify track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_verify_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_verify_2_sent
|
||||
name: "count_sent_third_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the verify track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_verify_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_verify_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_trial_0_sent
|
||||
name: "count_sent_first_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the trial track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_trial_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the verify trial's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_trial_1_sent
|
||||
name: "count_sent_second_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the trial track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_trial_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the trial track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_trial_2_sent
|
||||
name: "count_sent_third_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the trial track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_trial_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_trial_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the trial track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_team_0_sent
|
||||
name: "count_sent_first_email_of_the_trial_team_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the team track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_team_0_cta_clicked
|
||||
name: "count_clicks_on_the_first_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the team track's first email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_team_1_sent
|
||||
name: "count_sent_second_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the team track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_team_1_cta_clicked
|
||||
name: "count_clicks_on_the_second_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the team track's second email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_team_2_sent
|
||||
name: "count_sent_third_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total sent emails of the team track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.in_product_marketing_email_team_2_cta_clicked
|
||||
name: "count_clicks_on_the_third_email_of_the_team_track_for_in_product_marketing_emails"
|
||||
description: Total clicks on the team track's third email
|
||||
product_section:
|
||||
product_stage: growth
|
||||
product_group: group::activation
|
||||
product_category: onboarding
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.12"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddSnapshotNamespaceId < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :analytics_devops_adoption_snapshots, :namespace_id, :integer
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDisplayNamespaceIdToSegments < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :analytics_devops_adoption_segments, :display_namespace_id, :integer
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDevopsAdoptionIndexes < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
SEGMENTS_INDEX_NAME = 'idx_devops_adoption_segments_namespaces_pair'
|
||||
SNAPSHOT_END_TIME_INDEX_NAME = 'idx_devops_adoption_segments_namespace_end_time'
|
||||
SNAPSHOT_RECORDED_AT_INDEX_NAME = 'idx_devops_adoption_segments_namespace_recorded_at'
|
||||
|
||||
def up
|
||||
add_concurrent_index :analytics_devops_adoption_snapshots, [:namespace_id, :end_time],
|
||||
name: SNAPSHOT_END_TIME_INDEX_NAME
|
||||
add_concurrent_index :analytics_devops_adoption_snapshots, [:namespace_id, :recorded_at],
|
||||
name: SNAPSHOT_RECORDED_AT_INDEX_NAME
|
||||
add_concurrent_index :analytics_devops_adoption_segments, [:display_namespace_id, :namespace_id],
|
||||
unique: true, name: SEGMENTS_INDEX_NAME
|
||||
|
||||
add_concurrent_foreign_key :analytics_devops_adoption_snapshots, :namespaces, column: :namespace_id
|
||||
add_concurrent_foreign_key :analytics_devops_adoption_segments, :namespaces, column: :display_namespace_id
|
||||
end
|
||||
|
||||
def down
|
||||
remove_foreign_key :analytics_devops_adoption_segments, :namespaces, column: :display_namespace_id
|
||||
remove_foreign_key :analytics_devops_adoption_snapshots, :namespaces, column: :namespace_id
|
||||
|
||||
remove_concurrent_index_by_name :analytics_devops_adoption_segments, SEGMENTS_INDEX_NAME
|
||||
remove_concurrent_index_by_name :analytics_devops_adoption_snapshots, SNAPSHOT_RECORDED_AT_INDEX_NAME
|
||||
remove_concurrent_index_by_name :analytics_devops_adoption_snapshots, SNAPSHOT_END_TIME_INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveObsoleteSegmentsField < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_column :analytics_devops_adoption_segments, :name
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
add_column :analytics_devops_adoption_segments, :name, :text
|
||||
add_text_limit :analytics_devops_adoption_segments, :name, 255
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CopyAdoptionSnapshotNamespace < ActiveRecord::Migration[6.0]
|
||||
def up
|
||||
execute <<-SQL
|
||||
UPDATE analytics_devops_adoption_snapshots snapshots
|
||||
SET namespace_id = segments.namespace_id
|
||||
FROM analytics_devops_adoption_segments segments
|
||||
WHERE snapshots.namespace_id IS NULL AND segments.id = snapshots.segment_id
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute 'UPDATE analytics_devops_adoption_snapshots SET namespace_id = NULL'
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CopyAdoptionSegmentsNamespace < ActiveRecord::Migration[6.0]
|
||||
def up
|
||||
execute <<-SQL
|
||||
UPDATE analytics_devops_adoption_segments SET display_namespace_id = namespace_id
|
||||
WHERE display_namespace_id IS NULL
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute 'UPDATE analytics_devops_adoption_segments SET display_namespace_id = NULL'
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class CreateIndexOnNotesNote < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DUPLICATE_INDEX_NAME = 'index_notes_on_note_gin_trigram'
|
||||
CURRENT_INDEX_NAME = 'index_notes_on_note_trigram'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/218410#note_565624409
|
||||
# We are having troubles with the index, and some inserts are taking a long time
|
||||
# so in this migration we are recreating the index
|
||||
def up
|
||||
add_concurrent_index :notes, :note, name: DUPLICATE_INDEX_NAME, using: :gin, opclass: :gin_trgm_ops
|
||||
remove_concurrent_index_by_name :notes, CURRENT_INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index :notes, :note, name: CURRENT_INDEX_NAME, using: :gin, opclass: :gin_trgm_ops
|
||||
remove_concurrent_index_by_name :notes, DUPLICATE_INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
476dc70eae87ad3ee30e6be8c1afb4a2aec23a09b96daba2afbd9c4e2edb12b9
|
||||
|
|
@ -0,0 +1 @@
|
|||
ebdeb56647f3a7ff5620141833c90b796a9ddfed39234bcf8063ca5b3df6c1f3
|
||||
|
|
@ -0,0 +1 @@
|
|||
7f6862205e8c315da8433083fc5391f8889951f62d466e0048063322a46f9cc7
|
||||
|
|
@ -0,0 +1 @@
|
|||
c4a4b214f15a1a8d7f6832782d50077189281ca9a9b1b746a0a3bc3af4a47e3c
|
||||
|
|
@ -0,0 +1 @@
|
|||
77e2b8c1c6054a80122f97dda1e843149fefb7bf6694fdfa897d691d61162d81
|
||||
|
|
@ -0,0 +1 @@
|
|||
c5fe6f74822168599ad5069bb7c793ec96a4bba99d15ad29cb161ef24291b56d
|
||||
|
|
@ -0,0 +1 @@
|
|||
2d11da499f49964f37cc0a2c541cf58182416ae7b6b0e762a135b327099de1a4
|
||||
|
|
@ -9103,12 +9103,11 @@ ALTER SEQUENCE analytics_devops_adoption_segment_selections_id_seq OWNED BY anal
|
|||
|
||||
CREATE TABLE analytics_devops_adoption_segments (
|
||||
id bigint NOT NULL,
|
||||
name text,
|
||||
last_recorded_at timestamp with time zone,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
namespace_id integer,
|
||||
CONSTRAINT check_4be7a006fd CHECK ((char_length(name) <= 255))
|
||||
display_namespace_id integer
|
||||
);
|
||||
|
||||
CREATE SEQUENCE analytics_devops_adoption_segments_id_seq
|
||||
|
|
@ -9133,7 +9132,8 @@ CREATE TABLE analytics_devops_adoption_snapshots (
|
|||
security_scan_succeeded boolean NOT NULL,
|
||||
end_time timestamp with time zone NOT NULL,
|
||||
total_projects_count integer,
|
||||
code_owners_used_count integer
|
||||
code_owners_used_count integer,
|
||||
namespace_id integer
|
||||
);
|
||||
|
||||
CREATE SEQUENCE analytics_devops_adoption_snapshots_id_seq
|
||||
|
|
@ -22133,6 +22133,12 @@ CREATE INDEX idx_container_repositories_on_exp_cleanup_status_and_start_date ON
|
|||
|
||||
CREATE INDEX idx_deployment_clusters_on_cluster_id_and_kubernetes_namespace ON deployment_clusters USING btree (cluster_id, kubernetes_namespace);
|
||||
|
||||
CREATE INDEX idx_devops_adoption_segments_namespace_end_time ON analytics_devops_adoption_snapshots USING btree (namespace_id, end_time);
|
||||
|
||||
CREATE INDEX idx_devops_adoption_segments_namespace_recorded_at ON analytics_devops_adoption_snapshots USING btree (namespace_id, recorded_at);
|
||||
|
||||
CREATE UNIQUE INDEX idx_devops_adoption_segments_namespaces_pair ON analytics_devops_adoption_segments USING btree (display_namespace_id, namespace_id);
|
||||
|
||||
CREATE INDEX idx_eaprpb_external_approval_rule_id ON external_approval_rules_protected_branches USING btree (external_approval_rule_id);
|
||||
|
||||
CREATE INDEX idx_elastic_reindexing_slices_on_elastic_reindexing_subtask_id ON elastic_reindexing_slices USING btree (elastic_reindexing_subtask_id);
|
||||
|
|
@ -23667,7 +23673,7 @@ CREATE INDEX index_notes_on_discussion_id ON notes USING btree (discussion_id);
|
|||
|
||||
CREATE INDEX index_notes_on_line_code ON notes USING btree (line_code);
|
||||
|
||||
CREATE INDEX index_notes_on_note_trigram ON notes USING gin (note gin_trgm_ops);
|
||||
CREATE INDEX index_notes_on_note_gin_trigram ON notes USING gin (note gin_trgm_ops);
|
||||
|
||||
CREATE INDEX index_notes_on_noteable_id_and_noteable_type_and_system ON notes USING btree (noteable_id, noteable_type, system);
|
||||
|
||||
|
|
@ -25224,6 +25230,9 @@ ALTER TABLE ONLY project_features
|
|||
ALTER TABLE ONLY ci_pipelines
|
||||
ADD CONSTRAINT fk_190998ef09 FOREIGN KEY (external_pull_request_id) REFERENCES external_pull_requests(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY analytics_devops_adoption_segments
|
||||
ADD CONSTRAINT fk_190a24754d FOREIGN KEY (display_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY user_details
|
||||
ADD CONSTRAINT fk_190e4fcc88 FOREIGN KEY (provisioned_by_group_id) REFERENCES namespaces(id) ON DELETE SET NULL;
|
||||
|
||||
|
|
@ -25440,6 +25449,9 @@ ALTER TABLE ONLY users
|
|||
ALTER TABLE ONLY geo_event_log
|
||||
ADD CONSTRAINT fk_78a6492f68 FOREIGN KEY (repository_updated_event_id) REFERENCES geo_repository_updated_events(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY analytics_devops_adoption_snapshots
|
||||
ADD CONSTRAINT fk_78c9eac821 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY lists
|
||||
ADD CONSTRAINT fk_7a5553d60f FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ The following metrics are available:
|
|||
| `pipeline_graph_links_per_job_ratio` | Histogram | 13.9 | Ratio of links to job per graph | |
|
||||
| `gitlab_ci_pipeline_security_orchestration_policy_processing_duration_seconds` | Histogram | 13.12 | Time in seconds it takes to process Security Policies in CI/CD pipeline | |
|
||||
| `gitlab_ci_difference_live_vs_actual_minutes` | Histogram | 13.12 | Difference between CI minute consumption counted while jobs were running (live) vs when jobs are complete (actual). Used to enforce CI minute consumption limits on long running jobs. | `plan` |
|
||||
| `gitlab_spamcheck_request_duration_seconds` | Histogram | 13.12 | The duration for requests between Rails and the anti-spam engine | |
|
||||
|
||||
## Metrics controlled by a feature flag
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue