1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'rubygems'
require 'gitlab'
require 'optparse'
class JobFinder
DEFAULT_OPTIONS = {
project: ENV['CI_PROJECT_ID'],
pipeline_id: ENV['CI_PIPELINE_ID'],
pipeline_query: {},
job_query: {},
api_token: ENV['GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN']
}.freeze
def initialize(options)
@project = options.delete(:project)
@pipeline_query = options.delete(:pipeline_query)
@job_query = options.delete(:job_query)
@pipeline_id = options.delete(:pipeline_id)
@job_name = options.delete(:job_name)
@artifact_path = options.delete(:artifact_path)
# Force the token to be a string so that if api_token is nil, it's set to '', allowing unauthenticated requests (for forks).
api_token = options.delete(:api_token).to_s
warn "No API token given." if api_token.empty?
Gitlab.configure do |config|
config.endpoint = 'https://gitlab.com/api/v4'
config.private_token = api_token
end
end
def execute
find_job_with_artifact || find_job_with_filtered_pipelines || find_job_in_pipeline
end
private
attr_reader :project, :pipeline_query, :job_query, :pipeline_id, :job_name, :artifact_path
def find_job_with_artifact
return if artifact_path.nil?
Gitlab.pipelines(project, pipeline_query_params).auto_paginate do |pipeline|
Gitlab.pipeline_jobs(project, pipeline.id, job_query_params).auto_paginate do |job|
return job if found_job_with_artifact?(job) # rubocop:disable Cop/AvoidReturnFromBlocks
end
end
raise 'Job not found!'
end
def find_job_with_filtered_pipelines
return if pipeline_query.empty?
Gitlab.pipelines(project, pipeline_query_params).auto_paginate do |pipeline|
Gitlab.pipeline_jobs(project, pipeline.id, job_query_params).auto_paginate do |job|
return job if found_job_by_name?(job) # rubocop:disable Cop/AvoidReturnFromBlocks
end
end
raise 'Job not found!'
end
def find_job_in_pipeline
return unless pipeline_id
Gitlab.pipeline_jobs(project, pipeline_id, job_query_params).auto_paginate do |job|
return job if found_job_by_name?(job) # rubocop:disable Cop/AvoidReturnFromBlocks
end
raise 'Job not found!'
end
def found_job_with_artifact?(job)
artifact_url = "https://gitlab.com/api/v4/projects/#{CGI.escape(project)}/jobs/#{job.id}/artifacts/#{artifact_path}"
response = HTTParty.head(artifact_url) # rubocop:disable Gitlab/HTTParty
response.success?
end
def found_job_by_name?(job)
job.name == job_name
end
def pipeline_query_params
@pipeline_query_params ||= { per_page: 100, **pipeline_query }
end
def job_query_params
@job_query_params ||= { per_page: 100, **job_query }
end
end
if $0 == __FILE__
options = JobFinder::DEFAULT_OPTIONS.dup
OptionParser.new do |opts|
opts.on("-p", "--project PROJECT", String, "Project where to find the job (defaults to $CI_PROJECT_ID)") do |value|
options[:project] = value
end
opts.on("-i", "--pipeline-id pipeline_id", String, "A pipeline ID (defaults to $CI_PIPELINE_ID)") do |value|
options[:pipeline_id] = value
end
opts.on("-q", "--pipeline-query pipeline_query", String, "Query to pass to the Pipeline API request") do |value|
options[:pipeline_query].merge!(Hash[*value.split('=')])
end
opts.on("-Q", "--job-query job_query", String, "Query to pass to the Job API request") do |value|
options[:job_query].merge!(Hash[*value.split('=')])
end
opts.on("-j", "--job-name job_name", String, "A job name that needs to exist in the found pipeline") do |value|
options[:job_name] = value
end
opts.on("-a", "--artifact-path ARTIFACT_PATH", String, "A valid artifact path") do |value|
options[:artifact_path] = value
end
opts.on("-t", "--api-token API_TOKEN", String, "A value API token with the `read_api` scope") do |value|
options[:api_token] = value
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end.parse!
job = JobFinder.new(options).execute
return if job.nil?
puts job.id
end
|