Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-05 15:13:17 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-05 15:13:17 +0300
commitcd17aa65132de074aab9ae50ab7bbf7f16428546 (patch)
tree5a195a869320321aa9c3891e7ba5bbc9b9fc5d87 /scripts
parent508f0c4ee719abb1294684eea4a63aa44cd23597 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/create-pipeline-failure-incident.rb303
-rwxr-xr-xscripts/generate-failed-pipeline-slack-message.rb188
2 files changed, 0 insertions, 491 deletions
diff --git a/scripts/create-pipeline-failure-incident.rb b/scripts/create-pipeline-failure-incident.rb
deleted file mode 100755
index 05cba98d2fc..00000000000
--- a/scripts/create-pipeline-failure-incident.rb
+++ /dev/null
@@ -1,303 +0,0 @@
-#!/usr/bin/env ruby
-
-# frozen_string_literal: true
-
-require 'optparse'
-require 'json'
-
-require_relative 'api/commit_merge_requests'
-require_relative 'api/create_issue'
-require_relative 'api/create_issue_discussion'
-require_relative 'api/pipeline_failed_jobs'
-
-class CreatePipelineFailureIncident
- DEFAULT_OPTIONS = {
- project: nil,
- incident_json_file: 'incident.json'
- }.freeze
-
- def initialize(options)
- @project = options.delete(:project)
- @api_token = options.delete(:api_token)
- end
-
- def execute
- payload = {
- issue_type: 'incident',
- title: title,
- description: description,
- labels: incident_labels
- }
-
- payload[:assignee_ids] = assignee_ids if stable_branch_incident?
-
- CreateIssue.new(project: project, api_token: api_token).execute(payload).tap do |incident|
- CreateIssueDiscussion.new(project: project, api_token: api_token)
- .execute(issue_iid: incident.iid, body: "## Root Cause Analysis")
- CreateIssueDiscussion.new(project: project, api_token: api_token)
- .execute(issue_iid: incident.iid, body: "## Investigation Steps")
- end
- end
-
- private
-
- attr_reader :project, :api_token
-
- def stable_branch_incident?
- ENV['CI_COMMIT_REF_NAME'] =~ /^[\d-]+-stable(-ee)?$/
- end
-
- def review_apps_incident?
- project.end_with?('review-apps-broken-incidents')
- end
-
- def failed_jobs
- @failed_jobs ||= PipelineFailedJobs.new(API::DEFAULT_OPTIONS.merge(exclude_allowed_to_fail_jobs: true)).execute
- end
-
- def merge_request
- @merge_request ||= CommitMergeRequests.new(
- API::DEFAULT_OPTIONS.merge(sha: ENV['CI_COMMIT_SHA'])
- ).execute.first
- end
-
- def now
- @now ||= Time.now.utc
- end
-
- def title
- @title ||= begin
- full_title = "#{now.strftime('%A %F %R UTC')} - `#{ENV['CI_PROJECT_PATH']}` " \
- "broken `#{ENV['CI_COMMIT_REF_NAME']}` with #{failed_jobs.map(&:name).join(', ')}"
-
- if full_title.size >= 255
- "#{full_title[...252]}..." # max title length is 255, and we add an elipsis
- else
- full_title
- end
- end
- end
-
- def description
- if stable_branch_incident?
- broken_stable_description_content
- elsif review_apps_incident?
- broken_review_apps_description_content
- else
- broken_master_description_content
- end
- end
-
- def broken_master_description_content
- <<~MARKDOWN
- ## #{project_link} pipeline #{pipeline_link} failed
-
- **Branch: #{branch_link}**
-
- **Commit: #{commit_link}**
-
- **Triggered by** #{triggered_by_link} • **Source:** #{source} • **Duration:** #{pipeline_duration} minutes
-
- **Failed jobs (#{failed_jobs.size}):**
-
- #{failed_jobs_list}
-
- ### General guidelines
-
- Follow the [Broken `master` handbook guide](https://about.gitlab.com/handbook/engineering/workflow/#broken-master).
-
- ### Investigation
-
- **Be sure to fill the `Timeline` for this incident.**
-
- 1. If the failure is new, and looks like a potential flaky failure, you can retry the failing job.
- Make sure to mention the retry in the `Timeline` and leave a link to the retried job.
- 1. If the failure looks like a broken `master`, communicate the broken `master` in Slack using the "Broadcast Master Broken" workflow:
- - Click the Shortcut lightning bolt icon in the `#master-broken` channel and select "Broadcast Master Broken".
- - Click "Continue the broadcast" after the automated message in `#master-broken`.
-
- ### Pre-resolution
-
- If you believe that there's an easy resolution by either:
-
- - Reverting a particular merge request.
- - Making a quick fix (for example, one line or a few similar simple changes in a few lines).
- You can create a merge request, assign to any available maintainer, and ping people that were involved/related to the introduction of the failure.
- Additionally, a message can be posted in `#backend_maintainers` or `#frontend_maintainers` to get a maintainer take a look at the fix ASAP.
-
- In both cases, make sure to add the ~"pipeline:expedite" label, and `master:broken` or `master:foss-broken` label, to speed up the `master`-fixing pipelines.
-
- ### Resolution
-
- Follow [the Resolution steps from the handbook](https://about.gitlab.com/handbook/engineering/workflow/#responsibilities-of-the-resolution-dri).
- MARKDOWN
- end
-
- def broken_stable_description_content
- <<~MARKDOWN
- ## #{project_link} pipeline #{pipeline_link} failed
-
- **Branch: #{branch_link}**
-
- **Commit: #{commit_link}**
-
- **Merge Request: #{merge_request_link}**
-
- **Triggered by** #{triggered_by_link} • **Source:** #{source} • **Duration:** #{pipeline_duration} minutes
-
- **Failed jobs (#{failed_jobs.size}):**
-
- #{failed_jobs_list}
-
- ### General guidelines
-
- A broken stable branch prevents patch releases from being built.
- Fixing the pipeline is a priority to prevent any delays in releases.
-
- The process in the [Broken `master` handbook guide](https://about.gitlab.com/handbook/engineering/workflow/#broken-master) can be referenced since much of that process also applies here.
-
- ### Investigation
-
- **Be sure to fill the `Timeline` for this incident.**
-
- 1. If the failure is new, and looks like a potential flaky failure, you can retry the failing job.
- Make sure to mention the retry in the `Timeline` and leave a link to the retried job.
- 1. Search for similar master-broken issues in https://gitlab.com/gitlab-org/quality/engineering-productivity/master-broken-incidents/-/issues
- 1. If one exists, ask the DRI of the master-broken issue to cherry-pick any resulting merge requests into the stable branch
-
- @gitlab-org/release/managers if the merge request author or maintainer is not available, this can be escalated using the dev-on-call process in the [#dev-escalation slack channel](https://gitlab.slack.com/archives/CLKLMSUR4).
-
- ### Pre-resolution
-
- If you believe that there's an easy resolution by either:
-
- - Reverting a particular merge request.
- - Making a quick fix (for example, one line or a few similar simple changes in a few lines).
- You can create a merge request, assign to any available maintainer, and ping people that were involved/related to the introduction of the failure.
- Additionally, a message can be posted in `#backend_maintainers` or `#frontend_maintainers` to get a maintainer take a look at the fix ASAP.
- - Cherry picking a change that was used to fix a similar master-broken issue.
-
- ### Resolution
-
- Add a comment to this issue describing how this incident could have been prevented earlier in the Merge Request pipeline (rather than the merge commit pipeline).
-
- MARKDOWN
- end
-
- def broken_review_apps_description_content
- <<~MARKDOWN
- ## #{project_link} pipeline #{pipeline_link} failed
-
- **Branch: #{branch_link}**
-
- **Commit: #{commit_link}**
-
- **Triggered by** #{triggered_by_link} • **Source:** #{source} • **Duration:** #{pipeline_duration} minutes
-
- **Failed jobs (#{failed_jobs.size}):**
-
- #{failed_jobs_list}
-
- ### General guidelines
-
- Please refer to [the review-apps triaging process](https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/blob/main/runbooks/review-apps.md#review-apps-broken-slack-channel-isnt-empty).
- MARKDOWN
- end
-
- def incident_labels
- if stable_branch_incident?
- ['release-blocker']
- elsif review_apps_incident?
- ['review-apps-broken', 'Engineering Productivity', 'ep::review-apps']
- else
- master_broken_label =
- if ENV['CI_PROJECT_NAME'] == 'gitlab-foss'
- 'master:foss-broken'
- else
- 'master:broken'
- end
-
- [master_broken_label, 'Engineering Productivity', 'master-broken::undetermined']
- end
- end
-
- def assignee_ids
- ids = [ENV['GITLAB_USER_ID'].to_i]
- ids << merge_request['author']['id'].to_i if merge_request
- ids
- end
-
- def pipeline_link
- "[##{ENV['CI_PIPELINE_ID']}](#{ENV['CI_PIPELINE_URL']})"
- end
-
- def branch_link
- "[`#{ENV['CI_COMMIT_REF_NAME']}`](#{ENV['CI_PROJECT_URL']}/-/commits/#{ENV['CI_COMMIT_REF_NAME']})"
- end
-
- def pipeline_duration
- ((Time.now - Time.parse(ENV['CI_PIPELINE_CREATED_AT'])) / 60.to_f).round(2)
- end
-
- def commit_link
- "[#{ENV['CI_COMMIT_TITLE']}](#{ENV['CI_PROJECT_URL']}/-/commit/#{ENV['CI_COMMIT_SHA']})"
- end
-
- def merge_request_link
- return 'N/A' unless merge_request
-
- "[#{merge_request['title']}](#{merge_request['web_url']})"
- end
-
- def source
- "`#{ENV['CI_PIPELINE_SOURCE']}`"
- end
-
- def project_link
- "[#{ENV['CI_PROJECT_PATH']}](#{ENV['CI_PROJECT_URL']})"
- end
-
- def triggered_by_link
- "[#{ENV['GITLAB_USER_NAME']}](#{ENV['CI_SERVER_URL']}/#{ENV['GITLAB_USER_LOGIN']})"
- end
-
- def failed_jobs_list_for_title
- failed_jobs.map(&:name).join(', ')
- end
-
- def failed_jobs_list
- failed_jobs.map { |job| "- [#{job.name}](#{job.web_url})" }.join("\n")
- end
-end
-
-if $PROGRAM_NAME == __FILE__
- options = CreatePipelineFailureIncident::DEFAULT_OPTIONS.dup
-
- OptionParser.new do |opts|
- opts.on("-p", "--project PROJECT", String, "Project where to create the incident (defaults to "\
- "`#{CreatePipelineFailureIncident::DEFAULT_OPTIONS[:project]}`)") do |value|
- options[:project] = value
- end
-
- opts.on("-f", "--incident-json-file file_path", String, "Path to a file where to save the incident JSON data "\
- "(defaults to `#{CreatePipelineFailureIncident::DEFAULT_OPTIONS[:incident_json_file] || 'nil'}`)") do |value|
- options[:incident_json_file] = value
- end
-
- opts.on("-t", "--api-token API_TOKEN", String, "A valid Project token with the `Reporter` role and `api` scope "\
- "to create the incident") do |value|
- options[:api_token] = value
- end
-
- opts.on("-h", "--help", "Prints this help") do
- puts opts
- exit
- end
- end.parse!
-
- incident_json_file = options.delete(:incident_json_file)
-
- CreatePipelineFailureIncident.new(options).execute.tap do |incident|
- File.write(incident_json_file, JSON.pretty_generate(incident.to_h)) if incident_json_file
- end
-end
diff --git a/scripts/generate-failed-pipeline-slack-message.rb b/scripts/generate-failed-pipeline-slack-message.rb
deleted file mode 100755
index 2a406ad7e23..00000000000
--- a/scripts/generate-failed-pipeline-slack-message.rb
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/usr/bin/env ruby
-
-# frozen_string_literal: true
-
-require 'optparse'
-require 'json'
-
-require_relative 'api/pipeline_failed_jobs'
-
-class GenerateFailedPipelineSlackMessage
- DEFAULT_OPTIONS = {
- project: nil,
- failed_pipeline_slack_message_file: 'failed_pipeline_slack_message.json',
- incident_json_file: 'incident.json'
- }.freeze
-
- def initialize(options)
- @project = options.delete(:project)
- @incident_json_file = options.delete(:incident_json_file)
- end
-
- def execute
- {
- channel: ENV['SLACK_CHANNEL'],
- username: "Failed pipeline reporter",
- icon_emoji: ":boom:",
- text: "*#{title}*",
- blocks: [
- {
- type: "section",
- text: {
- type: "mrkdwn",
- text: "*#{title}*"
- },
- accessory: {
- type: "button",
- text: {
- type: "plain_text",
- text: incident_button_text
- },
- url: incident_button_link
- }
- },
- {
- type: "section",
- text: {
- type: "mrkdwn",
- text: "*Branch*: #{branch_link}"
- }
- },
- {
- type: "section",
- text: {
- type: "mrkdwn",
- text: "*Commit*: #{commit_link}"
- }
- },
- {
- type: "section",
- text: {
- type: "mrkdwn",
- text: "*Triggered by* #{triggered_by_link} • *Source:* #{source} • *Duration:* #{pipeline_duration} minutes"
- }
- },
- {
- type: "section",
- text: {
- type: "mrkdwn",
- text: "*Failed jobs (#{failed_jobs.size}):* #{failed_jobs_list}"
- }
- }
- ]
- }
- end
-
- private
-
- attr_reader :project, :incident_json_file
-
- def failed_jobs
- @failed_jobs ||= PipelineFailedJobs.new(API::DEFAULT_OPTIONS.dup.merge(exclude_allowed_to_fail_jobs: true)).execute
- end
-
- def title
- "#{project_link} pipeline #{pipeline_link} failed"
- end
-
- def incident_exist?
- return @incident_exist if defined?(@incident_exist)
-
- @incident_exist = File.exist?(incident_json_file)
- end
-
- def incident
- return unless incident_exist?
-
- @incident ||= JSON.parse(File.read(incident_json_file))
- end
-
- def incident_button_text
- if incident_exist?
- "View incident ##{incident['iid']}"
- else
- 'Create incident'
- end
- end
-
- def incident_button_link
- if incident_exist?
- incident['web_url']
- else
- "#{ENV['CI_SERVER_URL']}/#{project}/-/issues/new?" \
- "issuable_template=incident&issue%5Bissue_type%5D=incident"
- end
- end
-
- def pipeline_link
- "<#{ENV['CI_PIPELINE_URL']}|##{ENV['CI_PIPELINE_ID']}>"
- end
-
- def branch_link
- "<#{ENV['CI_PROJECT_URL']}/-/commits/#{ENV['CI_COMMIT_REF_NAME']}|`#{ENV['CI_COMMIT_REF_NAME']}`>"
- end
-
- def pipeline_duration
- ((Time.now - Time.parse(ENV['CI_PIPELINE_CREATED_AT'])) / 60.to_f).round(2)
- end
-
- def commit_link
- "<#{ENV['CI_PROJECT_URL']}/-/commit/#{ENV['CI_COMMIT_SHA']}|#{ENV['CI_COMMIT_TITLE']}>"
- end
-
- def source
- "`#{ENV['CI_PIPELINE_SOURCE']}#{schedule_type}`"
- end
-
- def schedule_type
- ENV['CI_PIPELINE_SOURCE'] == 'schedule' ? ": #{ENV['SCHEDULE_TYPE']}" : ''
- end
-
- def project_link
- "<#{ENV['CI_PROJECT_URL']}|#{ENV['CI_PROJECT_PATH']}>"
- end
-
- def triggered_by_link
- "<#{ENV['CI_SERVER_URL']}/#{ENV['GITLAB_USER_LOGIN']}|#{ENV['GITLAB_USER_NAME']}>"
- end
-
- def failed_jobs_list
- failed_jobs.map { |job| "<#{job.web_url}|#{job.name}>" }.join(', ')
- end
-end
-
-if $PROGRAM_NAME == __FILE__
- options = GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS.dup
-
- OptionParser.new do |opts|
- opts.on("-p", "--project PROJECT", String, "Full project path where the incidents are stored (defaults to "\
- "`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:project]}`)") do |value|
- options[:project] = value
- end
-
- opts.on("-i", "--incident-json-file file_path", String, "Path to a file where the incident JSON data "\
- "can be found (defaults to "\
- "`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:incident_json_file]}`)") do |value|
- options[:incident_json_file] = value
- end
-
- opts.on("-f", "--failed-pipeline-slack-message-file file_path", String, "Path to a file where to save the Slack "\
- "message (defaults to "\
- "`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:failed_pipeline_slack_message_file]}`)") do |value|
- options[:failed_pipeline_slack_message_file] = value
- end
-
- opts.on("-h", "--help", "Prints this help") do
- puts opts
- exit
- end
- end.parse!
-
- failed_pipeline_slack_message_file = options.delete(:failed_pipeline_slack_message_file)
-
- GenerateFailedPipelineSlackMessage.new(options).execute.tap do |message_payload|
- if failed_pipeline_slack_message_file
- File.write(failed_pipeline_slack_message_file, JSON.pretty_generate(message_payload))
- end
- end
-end