Skip to content
代码片段 群组 项目
未验证 提交 cc5b507e 编辑于 作者: David Dieulivol's avatar David Dieulivol 提交者: GitLab
浏览文件

Apply 4 suggestion(s) to 1 file(s)


Co-authored-by: default avatarLin Jen-Shin <jen-shin@gitlab.com>
上级 c152abe6
No related branches found
No related tags found
无相关合并请求
...@@ -66,7 +66,7 @@ set-pipeline-name: ...@@ -66,7 +66,7 @@ set-pipeline-name:
# We use > instead of | because we want the files to be space-separated. # We use > instead of | because we want the files to be space-separated.
FILES_TO_DOWNLOAD: > FILES_TO_DOWNLOAD: >
scripts/utils.sh scripts/utils.sh
scripts/pipeline/set-pipeline-name scripts/pipeline/set_pipeline_name.rb
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}-alpine3.16 image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}-alpine3.16
stage: prepare stage: prepare
before_script: before_script:
...@@ -75,7 +75,7 @@ set-pipeline-name: ...@@ -75,7 +75,7 @@ set-pipeline-name:
script: script:
- source scripts/utils.sh - source scripts/utils.sh
- install_gitlab_gem - install_gitlab_gem
- chmod u+x scripts/pipeline/set-pipeline-name && scripts/pipeline/set-pipeline-name - chmod u+x scripts/pipeline/set_pipeline_name.rb && scripts/pipeline/set_pipeline_name.rb
allow_failure: allow_failure:
exit_codes: exit_codes:
- 3 - 3
......
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true # frozen_string_literal: true
require 'gitlab' # We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab' unless Object.const_defined?(:Gitlab)
require 'net/http'
class SetPipelineName class SetPipelineName
DOCS = ['docs-lint markdown', 'docs-lint links'].freeze DOCS = ['docs-lint markdown', 'docs-lint links'].freeze
...@@ -28,83 +32,127 @@ class SetPipelineName ...@@ -28,83 +32,127 @@ class SetPipelineName
# Ordered by expected duration, DESC # Ordered by expected duration, DESC
PIPELINE_TYPES_ORDERED = %w[qa review-app qa-gdk code rspec-predictive docs].freeze PIPELINE_TYPES_ORDERED = %w[qa review-app qa-gdk code rspec-predictive docs].freeze
def initialize # We need an access token that isn't CI_JOB_TOKEN because we are querying
@pipeline_types = Set.new # the pipelines API to fetch jobs and bridge jobs.
# We are still using CI_JOB_TOKEN to update the pipeline name.
#
# See https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html for more info.
def initialize(api_endpoint:, gitlab_access_token:)
@api_endpoint = api_endpoint
@gitlab_access_token = gitlab_access_token
end end
def execute def gitlab
if ENV['CI_PIPELINE_NAME'].match?(/\[types: .+\]/) @gitlab ||= Gitlab.client(
puts "Pipeline name '#{ENV['CI_PIPELINE_NAME']}' already has types in its name." endpoint: @api_endpoint,
return private_token: @gitlab_access_token
end )
end
begin def execute
Gitlab.pipeline_bridges(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID']).auto_paginate do |job| # If we already added metadata to the pipeline name, we discard it, and recompute it.
@pipeline_types.merge(pipeline_types_for(job)) #
end # This is in case we retry a CI job that runs this script.
pipeline_name = ENV['CI_PIPELINE_NAME'].sub(/ \[.*\]\z/, '')
Gitlab.pipeline_jobs(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID']).auto_paginate do |job| pipeline_suffixes = {}
@pipeline_types.merge(pipeline_types_for(job)) pipeline_suffixes[:tier] = pipeline_tier || 'N/A'
end pipeline_suffixes[:types] = pipeline_types.join(',')
rescue Gitlab::Error::Error => error
puts "GitLab error: #{error}"
exit_allow_to_fail
end
pipeline_name = "#{ENV['CI_PIPELINE_NAME']} [types: #{sorted_pipeline_types.join(',')}]" pipeline_suffix = pipeline_suffixes.map { |key, value| "#{key}:#{value}" }.join(', ')
pipeline_name += " [#{pipeline_suffix}]"
puts "Found pipeline types: #{pipeline_types.to_a}"
puts "New pipeline name: #{pipeline_name}" puts "New pipeline name: #{pipeline_name}"
set_pipeline_name(pipeline_name) set_pipeline_name(pipeline_name)
rescue Gitlab::Error::Error => error
puts "GitLab error: #{error}"
allow_to_fail_return_code
end end
private private
attr_accessor :pipeline_types def pipeline_tier
return unless ENV['CI_MERGE_REQUEST_LABELS']
def pipeline_types_for(job) # The first pipeline of any MR won't have any tier label, unless the label was added in the MR description
pipeline_types = Set.new # before creating the MR. This is a known limitation.
pipeline_types << 'rspec-predictive' if RSPEC_PREDICTIVE.include?(job.name) #
pipeline_types << 'qa-gdk' if QA_GDK.include?(job.name) # Fetching the labels from the API instead of relying on ENV['CI_MERGE_REQUEST_LABELS']
pipeline_types << 'review-app' if REVIEW_APP.include?(job.name) # would solve this problem, but it would also mean that we would update the tier information
pipeline_types << 'qa' if QA.include?(job.name) # based on the merge request labels at the time of retrying the job, which isn't what we want.
pipeline_types << 'docs' if DOCS.include?(job.name) merge_request_labels = ENV['CI_MERGE_REQUEST_LABELS'].split(',')
pipeline_types << 'code' if CODE.include?(job.name) puts "Labels from the MR: #{merge_request_labels}"
pipeline_types
tier_label = merge_request_labels.find { |label| label.start_with?('pipeline::tier-') }
return if tier_label.nil?
tier_label[/\d+\z/]
end end
def sorted_pipeline_types def pipeline_types
pipeline_types.sort_by { |type| PIPELINE_TYPES_ORDERED.index(type) } types = Set.new
gitlab.pipeline_bridges(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID']).auto_paginate do |job|
types.merge(pipeline_types_for(job))
end
gitlab.pipeline_jobs(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID']).auto_paginate do |job|
types.merge(pipeline_types_for(job))
end
types.sort_by { |type| PIPELINE_TYPES_ORDERED.index(type) }
end
def pipeline_types_for(job)
types = Set.new
types << 'rspec-predictive' if RSPEC_PREDICTIVE.include?(job.name)
types << 'qa-gdk' if QA_GDK.include?(job.name)
types << 'review-app' if REVIEW_APP.include?(job.name)
types << 'qa' if QA.include?(job.name)
types << 'docs' if DOCS.include?(job.name)
types << 'code' if CODE.include?(job.name)
types
end end
def set_pipeline_name(pipeline_name) def set_pipeline_name(pipeline_name)
# TODO: Create an issue in the gitlab gem to add this one # TODO: Replace with the following once a version of the gem is above 4.19.0:
#
# Gitlab.update_pipeline_metadata(ENV['CI_PROJECT_ID'], ENV['CI_PIPELINE_ID'], name: pipeline_name)
#
# New endpoint added in https://github.com/NARKOZ/gitlab/pull/685 (merged on 2024-04-30)
# Latest release was made on 2022-07-10: https://github.com/NARKOZ/gitlab/releases/tag/v4.19.0
uri = URI("#{ENV['CI_API_V4_URL']}/projects/#{ENV['CI_PROJECT_ID']}/pipelines/#{ENV['CI_PIPELINE_ID']}/metadata") uri = URI("#{ENV['CI_API_V4_URL']}/projects/#{ENV['CI_PROJECT_ID']}/pipelines/#{ENV['CI_PIPELINE_ID']}/metadata")
success = false
error = nil
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
request = Net::HTTP::Put.new uri request = Net::HTTP::Put.new uri
request['JOB-TOKEN'] = ENV['CI_JOB_TOKEN'] request['JOB-TOKEN'] = ENV['CI_JOB_TOKEN']
request.body = "name=#{pipeline_name}" request.body = "name=#{pipeline_name}"
response = http.request request response = http.request request
if response.code != '200' if response.code == '200'
puts "Failed to set pipeline name: #{response.body}" success = true
exit_allow_to_fail else
error = response.body
end end
end end
return 0 if success
puts "Failed to set pipeline name: #{error}"
allow_to_fail_return_code
end end
# Exit with a different error code, so that we can allow the CI job to fail # Exit with a different error code, so that we can allow the CI job to fail
def exit_allow_to_fail def allow_to_fail_return_code
exit 3 3
end end
end end
if $PROGRAM_NAME == __FILE__ if $PROGRAM_NAME == __FILE__
Gitlab.configure do |config| exit SetPipelineName.new(
config.endpoint = ENV['CI_API_V4_URL'] api_endpoint: ENV['CI_API_V4_URL'],
config.private_token = ENV['PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE'] gitlab_access_token: ENV['PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE']
end ).execute
SetPipelineName.new.execute
end end
# frozen_string_literal: true
require 'fast_spec_helper'
require_relative '../../support/webmock'
require_relative '../../../scripts/pipeline/set_pipeline_name'
RSpec.describe SetPipelineName, feature_category: :tooling do
include StubENV
let(:instance) { described_class.new(api_endpoint: 'gitlab.test', gitlab_access_token: 'xxx') }
let(:original_pipeline_name) { "Ruby 3.2 MR" }
let(:project_id) { '123' }
let(:merge_request_iid) { '1234' }
let(:pipeline_id) { '5678' }
let(:merge_request_labels) { ['Engineering Productivity', 'type::feature', 'pipeline::tier-3'] }
let(:put_url) { "https://gitlab.test/api/v4/projects/#{project_id}/pipelines/#{pipeline_id}/metadata" }
let(:jobs) { ['docs-lint markdown'] }
let(:bridges) { ['rspec:predictive:trigger'] }
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
#
# rubocop:disable RSpec/VerifiedDoubles -- See the disclaimer above
before do
stub_env(
'CI_API_V4_URL' => 'https://gitlab.test/api/v4',
'CI_MERGE_REQUEST_IID' => merge_request_iid,
'CI_PIPELINE_ID' => pipeline_id,
'CI_PIPELINE_NAME' => original_pipeline_name,
'CI_PROJECT_ID' => project_id,
'PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE' => 'xxx',
'CI_MERGE_REQUEST_LABELS' => merge_request_labels.empty? ? nil : merge_request_labels.join(',')
)
stub_request(:put, put_url).to_return(status: 200, body: 'OK')
# Gitlab client stubbing
client = double('GitLab')
allow(instance).to receive(:gitlab).and_return(client)
allow(client).to yield_jobs(:pipeline_jobs, jobs)
allow(client).to yield_jobs(:pipeline_bridges, bridges)
# Ensure we don't output to stdout while running tests
allow(instance).to receive(:puts)
end
def yield_jobs(api_method, jobs)
messages = receive_message_chain(api_method, :auto_paginate)
jobs.inject(messages) do |stub, job_name|
stub.and_yield(double(name: job_name))
end
end
# rubocop:enable RSpec/VerifiedDoubles
describe '#execute' do
context 'when the pipeline is not from a merge request' do
let(:merge_request_iid) { nil }
let(:merge_request_labels) { [] }
it 'does not add a pipeline tier' do
instance.execute
expect(WebMock).to have_requested(:put, put_url).with { |req| req.body.include?('tier:N/A') }
end
it 'changes the pipeline types' do
instance.execute
# Why not a block with do..end? https://github.com/bblimke/webmock/issues/174#issuecomment-34908908
expect(WebMock).to have_requested(:put, put_url).with { |req|
req.body.include?('types:rspec-predictive,docs')
}
end
end
context 'when the pipeline is from a merge request' do
it 'adds a pipeline tier' do
instance.execute
expect(WebMock).to have_requested(:put, put_url).with { |req| req.body.include?('tier:3') }
end
it 'adds the pipeline types' do
instance.execute
# Why not a block with do..end? https://github.com/bblimke/webmock/issues/174#issuecomment-34908908
expect(WebMock).to have_requested(:put, put_url).with { |req|
req.body.include?('types:rspec-predictive,docs')
}
end
context 'when the merge request does not have a pipeline tier label' do
let(:merge_request_labels) { ['Engineering Productivity', 'type::feature'] }
it 'adds the N/A pipeline tier' do
instance.execute
expect(WebMock).to have_requested(:put, put_url).with { |req| req.body.include?('tier:N/A') }
end
end
end
end
context 'when we could not update the pipeline name' do
before do
stub_request(:put, put_url).to_return(status: 502, body: 'NOT OK')
end
it 'displays an error message' do
allow(instance).to receive(:puts).and_call_original
expect { instance.execute }.to output(/Failed to set pipeline name: NOT OK/).to_stdout
end
it 'returns an error code of 3' do
expect(instance.execute).to eq(3)
end
end
end
...@@ -24,7 +24,7 @@ def webmock_allowed_hosts ...@@ -24,7 +24,7 @@ def webmock_allowed_hosts
hosts << Gitlab.config.webpack.dev_server.host hosts << Gitlab.config.webpack.dev_server.host
end end
if ViteRuby.env['VITE_ENABLED'] == "true" if Object.const_defined?(:ViteRuby) && ViteRuby.env['VITE_ENABLED'] == "true"
hosts << ViteRuby.instance.config.host hosts << ViteRuby.instance.config.host
hosts << ViteRuby.env['VITE_HMR_HOST'] hosts << ViteRuby.env['VITE_HMR_HOST']
end end
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册