<commit_before>require 'json'
require 'shellwords'

module DPL
  class Provider
    module Heroku
      class API < Generic
        attr_reader :build_id

        def check_auth
          options = {
            method: :get,
            path: "/account",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200]
          }

          response = api.request(options).body
          user = response.fetch('email')
          log "authenticated as #{user}"
        end

        def push_app
          pack_archive
          upload_archive
          trigger_build
          verify_build
        end

        def archive_file
          Shellwords.escape("#{context.env['HOME']}/.dpl.#{option(:app)}.tgz")
        end

        def pack_archive
          log "creating application archive"
          context.shell "tar -zcf #{archive_file} --exclude .git ."
        end

        def upload_archive
          log "uploading application archive"
          context.shell "curl #{Shellwords.escape(put_url)} -X PUT -H 'Content-Type:' --data-binary @#{archive_file}"
        end

        def trigger_build
          log "triggering new deployment"
          response   = post(:builds, source_blob: { url: get_url, version: version })
          @build_id  = response.fetch('id')
          output_stream_url = response.fetch('output_stream_url')
          context.shell "curl #{Shellwords.escape(output_stream_url)}"
        end

        def verify_build
          loop do
            response = get("builds/#{build_id}/result")
            exit_code = response.fetch('exit_code')
            if exit_code.nil?
              log "heroku build still pending"
              sleep 5
              next
            elsif exit_code == 0
              break
            else
              error "deploy failed, build exited with code #{exit_code}"
            end
          end
        end

        def get_url
          source_blob.fetch("get_url")
        end

        def put_url
          source_blob.fetch("put_url")
        end

        def source_blob
          @source_blob ||= post(:sources).fetch("source_blob")
        end

        def version
          @version ||= options[:version] || context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
        end

        def get(subpath, options = {})
          options = {
            method: :get,
            path: "/apps/#{option(:app)}/#{subpath}",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200]
          }.merge(options)

          api.request(options).body
        end

        def post(subpath, body = nil, options = {})
          options = {
            method: :post,
            path: "/apps/#{option(:app)}/#{subpath}",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200, 201]
          }.merge(options)

          if body
            options[:body]                    = JSON.dump(body)
            options[:headers]['Content-Type'] = 'application/json'
          end

          api.request(options).body
        end
      end
    end
  end
end<commit_msg>Implement `#run` and `#start` options in Heroku API V3<commit_after>require 'json'
require 'shellwords'

module DPL
  class Provider
    module Heroku
      class API < Generic
        attr_reader :build_id

        def check_auth
          options = {
            method: :get,
            path: "/account",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200]
          }

          response = api.request(options).body
          user = response.fetch('email')
          log "authenticated as #{user}"
        end

        def push_app
          pack_archive
          upload_archive
          trigger_build
          verify_build
        end

        def archive_file
          Shellwords.escape("#{context.env['HOME']}/.dpl.#{option(:app)}.tgz")
        end

        def pack_archive
          log "creating application archive"
          context.shell "tar -zcf #{archive_file} --exclude .git ."
        end

        def upload_archive
          log "uploading application archive"
          context.shell "curl #{Shellwords.escape(put_url)} -X PUT -H 'Content-Type:' --data-binary @#{archive_file}"
        end

        def trigger_build
          log "triggering new deployment"
          response   = post(:builds, source_blob: { url: get_url, version: version })
          @build_id  = response.fetch('id')
          output_stream_url = response.fetch('output_stream_url')
          context.shell "curl #{Shellwords.escape(output_stream_url)}"
        end

        def verify_build
          loop do
            response = get("builds/#{build_id}/result")
            exit_code = response.fetch('exit_code')
            if exit_code.nil?
              log "heroku build still pending"
              sleep 5
              next
            elsif exit_code == 0
              break
            else
              error "deploy failed, build exited with code #{exit_code}"
            end
          end
        end

        def get_url
          source_blob.fetch("get_url")
        end

        def put_url
          source_blob.fetch("put_url")
        end

        def source_blob
          @source_blob ||= post(:sources).fetch("source_blob")
        end

        def version
          @version ||= options[:version] || context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
        end

        def get(subpath, options = {})
          options = {
            method: :get,
            path: "/apps/#{option(:app)}/#{subpath}",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200]
          }.merge(options)

          api.request(options).body
        end

        def post(subpath, body = nil, options = {})
          options = {
            method: :post,
            path: "/apps/#{option(:app)}/#{subpath}",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200, 201]
          }.merge(options)

          if body
            options[:body]                    = JSON.dump(body)
            options[:headers]['Content-Type'] = 'application/json'
          end

          response = api.request(options).body
        end

        def restart
          options = {
            method: :delete,
            path: "/apps/#{option(:app)}/dynos",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            expects: [200, 201, 202]
          }.merge(options)

          api.request(options).body
        end

        def run(command)
          options = {
            method: :post,
            path: "/apps/#{option(:app)}/dynos",
            headers: { "Accept" => "application/vnd.heroku+json; version=3" },
            attach: true,
            command: command,
            expects: [200, 201]
          }

          api.request(options).body
        end
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.11265410230976336, 'fraction_numerical': 0.007368570213971943, 'mean_word_length': 1.5862953462806888, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7564218', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1898, 'n_words': 450}