require 'base64' require 'json' require 'open-uri' require 'uri' class GitLabRawIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor @@prefix = 'gitlab:' def handles? target target.start_with? @@prefix end def warn_or_raise doc, warning if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read') raise warning else warn warning end end def process doc, reader, target, attrs src = target.delete_prefix(@@prefix).split('/', 2) owner = src.at 0 repo = src.at 1 namespaced_repo = "#{owner}/#{repo}" raise %(there is no 'path' attribute given for GitLab repo '#{namespaced_repo}') unless (attrs.key? 'path') raise %(no given ref for getting file in '#{namespaced_repo}') unless (attrs.key? 'rev') path = attrs['path'] rev = attrs['rev'] domain = attrs['domain'] || 'gitlab.com' version = attrs['version'] || 'v4' uri = URI.parse %(https://#{domain}/api/#{version}) # Set the project. uri += %(/projects/#{URI.encode_www_form_component namespaced_repo}) # Then the filename. uri += %(/repository/files/#{URI.encode_www_form_component path}) # Then the revision. query = { :ref => rev } uri.query = URI.encode_www_form query begin OpenURI.open_uri( uri, 'Content-Type' => 'application/json', 'PRIVATE-TOKEN' => ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'], ) do |f| response = JSON.parse(f.read) if response['content'] && response['encoding'] == 'base64' Base64.decode64 response['content'] end reader.push_include content, target, target, 1, attrs end rescue OpenURI::HTTPError => e warning = %(error while getting '#{path}' in GitLab repo '#{repo}': #{e}) warn_or_raise doc, warning reader.push_include warning, target, target, 1, attrs end reader end end