require 'net/http'
require 'uri'
module Danger
# Get access to Jenkins information right into your Dangerfile
#
# @example Configure credentials to access the Jenkins API
# jenkins.user_id = YOUR_USER_ID
# jenkins.api_token = YOUR_API_TOKEN
#
# @example Print list of artifacts in the PR page
# jenkins.print_artifacts
#
# @example Print console output in the PR page
# jenkins.print_console_output
#
# @example Get access to the build properties
# message "The spent #{jenkins.build.duration} time"
#
# @example Customize how you want to present the console output
# markdown "### Console output: \n\n #{jenkins.console_text}"
#
# @see thiagofelix/danger-jenkins
# @tags jenkins
#
class DangerJenkins < Plugin
JENKINS_ICON = 'https://wiki.jenkins-ci.org/download/attachments/2916393/headshot.png'.freeze
# User to authenticate with Jenkins REST API
#
# @return String
attr_accessor :user_id
# API token to authenticate with Jenkins REST API
#
# @return String
attr_accessor :api_token
def initialize(dangerfile)
super(dangerfile)
@env = dangerfile.env
@user_id = ENV['JENKINS_USER_ID']
@api_token = ENV['JENKINS_API_TOKEN']
@build_url = ENV['BUILD_URL']
raise 'Invalid CI for Jenkins plugin.' unless jenkins?
raise "Can't find current build" if @build_url.nil?
end
# Hash containing details about the build which triggered
# the danger process
#
# @return OpenStruct
def build
@current_build ||= fetch_current_build
end
# Console output in html format
#
# @return String
def console_html
@console_html_format ||= fetch_console(:html)
end
# Console output in text format
#
# @return String
def console_text
@console_text_format ||= fetch_console(:text)
end
# Adds a list of artifacts to the danger comment
#
# @return [void]
#
def print_artifacts
artifacts = build.artifacts
return if artifacts.empty?
content = "### Jenkins artifacts:\n\n"
content << "\n"
artifacts.each do |artifact|
content << "* #{artifact_link(artifact)}\n"
end
markdown content
end
# Adds a collapsable console output to danger comment
#
# @return [void]
#
def print_console_output
content = "### Jenkins console output:\n\n"
content << ''
content << 'Details
'
content << "#{console_html}
"
content << ' '
markdown content
end
private
def jenkins?
!@env.ci_source.nil? && @env.ci_source.is_a?(Danger::Jenkins)
end
def artifact_link(artifact)
href = "#{@build_url}/artifact/#{artifact.relativePath}"
"#{artifact.relativePath}"
end
def fetch_console(type = :text)
case type
when :text then
fetch("#{@build_url}/logText/progressiveText")
when :html then
fetch("#{@build_url}/logText/progressiveHtml")
end
end
def fetch_current_build
url = "#{@build_url}/api/json"
body = fetch(url)
JSON.parse(body, object_class: OpenStruct)
end
def fetch(url, limit = 10)
res = request(url)
case res
when Net::HTTPSuccess then
res.body
when Net::HTTPRedirection then
fetch(res['location'], limit - 1)
else
res.value
end
end
def request(url)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Get.new(uri.request_uri)
req.basic_auth(@user_id, @api_token)
http.request(req)
end
end
end