2020-11-25 10:09:13 -05:00
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'gitlab'
require 'optparse'
2021-08-16 02:09:08 -04:00
require_relative 'default_options'
2020-11-25 10:09:13 -05:00
class JobFinder
2021-08-16 02:09:08 -04:00
DEFAULT_OPTIONS = API :: DEFAULT_OPTIONS . merge (
pipeline_query : { } . freeze ,
job_query : { } . freeze
) . freeze
2021-11-25 13:14:13 -05:00
MAX_PIPELINES_TO_ITERATE = 20
2020-11-25 10:09:13 -05:00
def initialize ( options )
@project = options . delete ( :project )
2021-01-21 07:09:05 -05:00
@pipeline_query = options . delete ( :pipeline_query ) || DEFAULT_OPTIONS [ :pipeline_query ]
@job_query = options . delete ( :job_query ) || DEFAULT_OPTIONS [ :job_query ]
2020-11-25 10:09:13 -05:00
@pipeline_id = options . delete ( :pipeline_id )
@job_name = options . delete ( :job_name )
2020-12-09 10:10:12 -05:00
@artifact_path = options . delete ( :artifact_path )
2020-12-01 13:09:42 -05:00
# 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?
2020-11-25 10:09:13 -05:00
2021-08-16 02:09:08 -04:00
@client = Gitlab . client (
endpoint : options . delete ( :endpoint ) || DEFAULT_OPTIONS [ :endpoint ] ,
private_token : api_token
)
2020-11-25 10:09:13 -05:00
end
def execute
2020-12-09 10:10:12 -05:00
find_job_with_artifact || find_job_with_filtered_pipelines || find_job_in_pipeline
2020-11-25 10:09:13 -05:00
end
private
2021-08-16 02:09:08 -04:00
attr_reader :project , :pipeline_query , :job_query , :pipeline_id , :job_name , :artifact_path , :client
2020-12-09 10:10:12 -05:00
def find_job_with_artifact
return if artifact_path . nil?
2021-11-24 19:10:49 -05:00
client . pipelines ( project , pipeline_query_params ) . paginate_with_limit ( MAX_PIPELINES_TO_ITERATE ) do | pipeline |
$stderr . puts " Iterating over #{ pipeline } " # rubocop:disable Style/StderrPuts
2021-08-16 02:09:08 -04:00
client . pipeline_jobs ( project , pipeline . id , job_query_params ) . auto_paginate do | job |
2021-11-24 19:10:49 -05:00
next if job_name && ! found_job_by_name? ( job )
2020-12-09 10:10:12 -05:00
return job if found_job_with_artifact? ( job ) # rubocop:disable Cop/AvoidReturnFromBlocks
end
end
2021-11-25 13:14:13 -05:00
warn 'Job not found!'
2020-12-09 10:10:12 -05:00
end
2020-11-25 10:09:13 -05:00
def find_job_with_filtered_pipelines
return if pipeline_query . empty?
2021-11-24 19:10:49 -05:00
client . pipelines ( project , pipeline_query_params ) . paginate_with_limit ( MAX_PIPELINES_TO_ITERATE ) do | pipeline |
2021-08-16 02:09:08 -04:00
client . pipeline_jobs ( project , pipeline . id , job_query_params ) . auto_paginate do | job |
2020-12-09 10:10:12 -05:00
return job if found_job_by_name? ( job ) # rubocop:disable Cop/AvoidReturnFromBlocks
2020-11-25 10:09:13 -05:00
end
end
2021-11-25 13:14:13 -05:00
warn 'Job not found!'
2020-11-25 10:09:13 -05:00
end
def find_job_in_pipeline
return unless pipeline_id
2021-08-16 02:09:08 -04:00
client . pipeline_jobs ( project , pipeline_id , job_query_params ) . auto_paginate do | job |
2020-12-09 10:10:12 -05:00
return job if found_job_by_name? ( job ) # rubocop:disable Cop/AvoidReturnFromBlocks
2020-11-25 10:09:13 -05:00
end
2021-11-25 13:14:13 -05:00
warn 'Job not found!'
2020-11-25 10:09:13 -05:00
end
2020-12-09 10:10:12 -05:00
def found_job_with_artifact? ( job )
2021-08-16 02:09:08 -04:00
artifact_url = " #{ client . endpoint } /projects/ #{ CGI . escape ( project ) } /jobs/ #{ job . id } /artifacts/ #{ artifact_path } "
2020-12-09 10:10:12 -05:00
response = HTTParty . head ( artifact_url ) # rubocop:disable Gitlab/HTTParty
response . success?
end
def found_job_by_name? ( job )
job . name == job_name
end
2020-11-25 10:09:13 -05:00
def pipeline_query_params
2021-11-25 13:14:13 -05:00
@pipeline_query_params || = { per_page : MAX_PIPELINES_TO_ITERATE , ** pipeline_query }
2020-11-25 10:09:13 -05:00
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 |
2021-08-16 02:09:08 -04:00
options [ :pipeline_query ] =
options [ :pipeline_query ] . merge ( Hash [ * value . split ( '=' ) ] )
2020-11-25 10:09:13 -05:00
end
opts . on ( " -Q " , " --job-query job_query " , String , " Query to pass to the Job API request " ) do | value |
2021-08-16 02:09:08 -04:00
options [ :job_query ] =
options [ :job_query ] . merge ( Hash [ * value . split ( '=' ) ] )
2020-11-25 10:09:13 -05:00
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
2020-12-09 10:10:12 -05:00
opts . on ( " -a " , " --artifact-path ARTIFACT_PATH " , String , " A valid artifact path " ) do | value |
options [ :artifact_path ] = value
end
2020-11-25 10:09:13 -05:00
opts . on ( " -t " , " --api-token API_TOKEN " , String , " A value API token with the `read_api` scope " ) do | value |
options [ :api_token ] = value
end
2021-08-16 02:09:08 -04:00
opts . on ( " -E " , " --endpoint ENDPOINT " , String , " The API endpoint for the API token. (defaults to $CI_API_V4_URL and fallback to https://gitlab.com/api/v4) " ) do | value |
options [ :endpoint ] = value
end
2020-11-25 10:09:13 -05:00
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