robot_sweatshop 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -8
- data/bin/sweatshop +1 -1
- data/bin/sweatshop-input-http +8 -7
- data/bin/sweatshop-job-assembler +78 -41
- data/bin/sweatshop-job-worker +1 -1
- data/bin/sweatshop-payload-parser +67 -18
- data/config.defaults.yaml +3 -0
- data/kintama/data/git_job.yaml +9 -0
- data/kintama/data/payload_data.yaml +3 -2
- data/kintama/data/test_job.yaml +2 -4
- data/kintama/end-to-end_spec.rb +3 -6
- data/kintama/input_http_spec.rb +18 -14
- data/kintama/job_assembler_spec.rb +48 -48
- data/kintama/payload_parser_spec.rb +34 -43
- data/kintama/shared/helpers.rb +43 -18
- data/kintama/shared/process_spawning.rb +2 -2
- data/lib/README.md +11 -2
- data/lib/sweatshop/cli/job.rb +1 -1
- data/lib/sweatshop/cli.rb +4 -0
- data/lib/sweatshop/moneta-queue.rb +1 -1
- data/lib/sweatshop/payload/json.rb +13 -0
- data/lib/sweatshop/payload.rb +4 -0
- data/lib/sweatshop.rb +2 -13
- data/robot_sweatshop.gemspec +3 -2
- metadata +21 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: cbc73c13d57e32651f63077a89b03317769850f3
         | 
| 4 | 
            +
              data.tar.gz: 834bb91075c655c1edc0ac7f4cc445c2048094db
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 16784f92f5abe86c20dd6aebe73d79d3d9d18296576ba50ed0018467b205038fb67517a18931a539b4309839f311427b079c5b3b0e4708f7120d7e0baf570365
         | 
| 7 | 
            +
              data.tar.gz: bc6eca3c50fddb92091e7693b7f4aba3232ab96b857a3b495d7a20e557bff3f695cda3149842b718d5c5905011d04bdb4d6d9decaf3cca8a7dcd3c062b8a2e1e
         | 
    
        data/README.md
    CHANGED
    
    | @@ -8,11 +8,11 @@ Robot Sweatshop is a single-purpose CI server that runs collections of arbitrary | |
| 8 8 |  | 
| 9 9 | 
             
            # Quick start
         | 
| 10 10 |  | 
| 11 | 
            -
            - install [ZMQ as described in the EZMQ gem](https://github.com/colstrom/ezmq)
         | 
| 11 | 
            +
            - install [ZMQ as described in the EZMQ gem](https://github.com/colstrom/ezmq#operating-system-notes)
         | 
| 12 12 | 
             
            - `gem install robot_sweatshop`
         | 
| 13 13 | 
             
            - `sweatshop start` ([you may need sudo on OSX](https://github.com/JScott/robot_sweatshop/wiki))
         | 
| 14 14 | 
             
            - `sweatshop job example --auto`
         | 
| 15 | 
            -
            -  | 
| 15 | 
            +
            - `curl --data '{"your": "json"}' http://localhost:8080/payload-for/example`
         | 
| 16 16 | 
             
            - `cat .robot_sweatshop/log/job-worker.log`
         | 
| 17 17 |  | 
| 18 18 | 
             
            # Usage
         | 
| @@ -29,6 +29,7 @@ By default, Robot Sweatshop looks in your current working directory to configure | |
| 29 29 |  | 
| 30 30 | 
             
            - Github (application/json format only)
         | 
| 31 31 | 
             
            - Bitbucket
         | 
| 32 | 
            +
            - JSON
         | 
| 32 33 |  | 
| 33 34 | 
             
            # Security
         | 
| 34 35 |  | 
| @@ -36,12 +37,17 @@ You probably don't want to run Robot Sweatshop as a sudo user. Create a testing | |
| 36 37 |  | 
| 37 38 | 
             
            # Roadmap
         | 
| 38 39 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
            - Common scrips such as git repo syncing and creating a job run ID
         | 
| 42 | 
            -
            - Support for multiple workers
         | 
| 43 | 
            -
            - Better logging for the processes
         | 
| 44 | 
            -
            - Use [eye-http](https://github.com/kostya/eye-http) for the '/' route?
         | 
| 40 | 
            +
            1.0
         | 
| 41 | 
            +
             | 
| 45 42 | 
             
            - Improved architecture:
         | 
| 46 43 |  | 
| 47 44 | 
             
            
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            - Support for multiple workers
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            Beyond
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            - Better logging for the processes
         | 
| 51 | 
            +
            - CLI configuration via chomp and/or flags
         | 
| 52 | 
            +
            - Common scrips such as git repo syncing and creating a job run ID
         | 
| 53 | 
            +
            - Use [eye-http](https://github.com/kostya/eye-http) for the '/' route?
         | 
    
        data/bin/sweatshop
    CHANGED
    
    | @@ -10,7 +10,7 @@ require_relative '../lib/sweatshop/config' | |
| 10 10 | 
             
            require_relative '../lib/sweatshop/create-config-directories'
         | 
| 11 11 |  | 
| 12 12 | 
             
            program :name, 'Robot Sweatshop'
         | 
| 13 | 
            -
            program :version, '0. | 
| 13 | 
            +
            program :version, '0.3.0'
         | 
| 14 14 | 
             
            program :description, 'A lightweight, unopinionated CI server'
         | 
| 15 15 | 
             
            program :help, 'Author', 'Justin Scott <jvscott@gmail.com>'
         | 
| 16 16 |  | 
    
        data/bin/sweatshop-input-http
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            require 'bundler/setup'
         | 
| 2 3 | 
             
            require 'sinatra'
         | 
| 3 4 | 
             
            require 'ezmq'
         | 
| 4 5 | 
             
            require 'json'
         | 
| 5 | 
            -
             | 
| 6 | 
            +
            require 'sweatshop/config'
         | 
| 6 7 |  | 
| 7 8 | 
             
            configure do
         | 
| 8 9 | 
             
              set :port, configatron.http_port
         | 
| 9 10 | 
             
              set :bind, configatron.http_bind
         | 
| 10 | 
            -
              set :output_queue, 'raw-payload'
         | 
| 11 11 | 
             
              set :run, true
         | 
| 12 12 | 
             
            end
         | 
| 13 13 |  | 
| @@ -15,14 +15,15 @@ get '/' do | |
| 15 15 | 
             
              'Everything\'s on schedule!'
         | 
| 16 16 | 
             
            end
         | 
| 17 17 |  | 
| 18 | 
            -
            post ' | 
| 19 | 
            -
              puts "Received  | 
| 18 | 
            +
            post '/payload-for/:job_name' do
         | 
| 19 | 
            +
              puts "Received payload for #{params['job_name']}"
         | 
| 20 20 | 
             
              request.body.rewind
         | 
| 21 | 
            +
              payload = request.body.read
         | 
| 21 22 | 
             
              hash = {
         | 
| 22 | 
            -
                payload:  | 
| 23 | 
            -
                 | 
| 23 | 
            +
                payload: payload,
         | 
| 24 | 
            +
                user_agent: request.env['HTTP_USER_AGENT'],
         | 
| 24 25 | 
             
                job_name: params['job_name']
         | 
| 25 26 | 
             
              }
         | 
| 26 27 | 
             
              client = EZMQ::Client.new port: 5556
         | 
| 27 | 
            -
              client.request " | 
| 28 | 
            +
              client.request "payload #{JSON.generate hash}"
         | 
| 28 29 | 
             
            end
         | 
    
        data/bin/sweatshop-job-assembler
    CHANGED
    
    | @@ -1,45 +1,82 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            require 'bundler/setup'
         | 
| 2 3 | 
             
            require 'yaml'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
            def  | 
| 19 | 
            -
               | 
| 20 | 
            -
            end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
              return  | 
| 25 | 
            -
               | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
              puts " | 
| 41 | 
            -
               | 
| 4 | 
            +
            require 'json'
         | 
| 5 | 
            +
            require 'contracts'
         | 
| 6 | 
            +
            require 'sweatshop/queue-helper'
         | 
| 7 | 
            +
            require 'sweatshop/config'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            $stdout.sync = true
         | 
| 10 | 
            +
            include Contracts
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            Contract None => Hash
         | 
| 13 | 
            +
            def empty_config
         | 
| 14 | 
            +
              puts "Job configuration not found"
         | 
| 15 | 
            +
              {}
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Contract None => String
         | 
| 19 | 
            +
            def job_directory
         | 
| 20 | 
            +
              File.expand_path configatron.job_directory
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            Contract Or[String, nil], Hash => Bool
         | 
| 24 | 
            +
            def whitelisted?(branch, in_config:)
         | 
| 25 | 
            +
              return true if in_config['branch_whitelist'].nil?
         | 
| 26 | 
            +
              in_config['branch_whitelist'].include? branch
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            Contract Hash => Hash
         | 
| 30 | 
            +
            def sanitize(data)
         | 
| 31 | 
            +
              data.each_pair { |key, value| data[key] = value.to_s }
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Contract Hash, Hash => Hash
         | 
| 35 | 
            +
            def job_context(job_environment, context_from_payload)
         | 
| 36 | 
            +
              sanitize job_environment.merge(context_from_payload)
         | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            Contract String => Or[Hash, nil]
         | 
| 40 | 
            +
            def load_if_exists(config)
         | 
| 41 | 
            +
              puts "Reading job configuration from #{config}"
         | 
| 42 | 
            +
              YAML.load_file config if File.exists? config
         | 
| 43 | 
            +
            end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            Contract String => Hash
         | 
| 46 | 
            +
            def load_config_for(job_name)
         | 
| 47 | 
            +
              load_if_exists("#{job_directory}/#{job_name}.yaml") || empty_config
         | 
| 48 | 
            +
            end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            Contract Hash => [Hash, String]
         | 
| 51 | 
            +
            def parse_payload(request)
         | 
| 52 | 
            +
              client = EZMQ::Client.new port: configatron.payload_parser_port
         | 
| 53 | 
            +
              response = JSON.load client.request(JSON.dump request)
         | 
| 54 | 
            +
              puts response['error'] unless response['error'].empty?
         | 
| 55 | 
            +
              [response['payload'], response['error']]
         | 
| 56 | 
            +
            end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            Contract Hash, Hash => Bool
         | 
| 59 | 
            +
            def can_work_with?(job_config, payload)
         | 
| 60 | 
            +
              return false if job_config.empty?
         | 
| 61 | 
            +
              return false unless whitelisted? payload['branch'], in_config: job_config
         | 
| 62 | 
            +
              true
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            Contract Hash => Or[Hash, false]
         | 
| 66 | 
            +
            def assemble_job(request)
         | 
| 67 | 
            +
              job_config = load_config_for request['job_name']
         | 
| 68 | 
            +
              payload, error = parse_payload request
         | 
| 69 | 
            +
              return false unless error.empty? && can_work_with?(job_config, payload)
         | 
| 70 | 
            +
              {
         | 
| 71 | 
            +
                commands: job_config['commands'],
         | 
| 72 | 
            +
                context: job_context(job_config['environment'], payload),
         | 
| 73 | 
            +
                job_name: request['job_name']
         | 
| 74 | 
            +
              }
         | 
| 75 | 
            +
            end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            puts 'Started'
         | 
| 78 | 
            +
            QueueHelper.wait_for('payload') do |request|
         | 
| 79 | 
            +
              puts "Assembling: #{request}"
         | 
| 80 | 
            +
              assembled_job = assemble_job request
         | 
| 42 81 | 
             
              QueueHelper.enqueue assembled_job, to: 'jobs' if assembled_job
         | 
| 43 | 
            -
              $stdout.flush
         | 
| 44 | 
            -
              $stderr.flush
         | 
| 45 82 | 
             
            end
         | 
    
        data/bin/sweatshop-job-worker
    CHANGED
    
    | @@ -21,7 +21,7 @@ end | |
| 21 21 | 
             
            def execute(context = {}, command)
         | 
| 22 22 | 
             
              puts "Executing '#{command}'..."
         | 
| 23 23 | 
             
              # TODO: path.split(' ') to bypass the shell when we're not using env vars
         | 
| 24 | 
            -
             | 
| 24 | 
            +
             | 
| 25 25 | 
             
              # Run the command with the context in environment,
         | 
| 26 26 | 
             
              # printing the output as it's generated
         | 
| 27 27 | 
             
              IO.popen(context, command) do |io_stream|
         | 
| @@ -1,23 +1,72 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 2 | 
            +
            require 'bundler/setup'
         | 
| 3 | 
            +
            require 'json'
         | 
| 4 | 
            +
            require 'ezmq'
         | 
| 5 | 
            +
            require 'contracts'
         | 
| 6 | 
            +
            require 'sweatshop/config'
         | 
| 7 | 
            +
            require 'sweatshop/payload'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            $stdout.sync = true
         | 
| 10 | 
            +
            include Contracts
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            Contract String => Bool
         | 
| 13 | 
            +
            def json?(string)
         | 
| 14 | 
            +
              begin
         | 
| 15 | 
            +
                JSON.load string
         | 
| 16 | 
            +
                true
         | 
| 17 | 
            +
              rescue JSON::ParserError => e
         | 
| 18 | 
            +
                false
         | 
| 13 19 | 
             
              end
         | 
| 14 20 | 
             
            end
         | 
| 15 21 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
               | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 22 | 
            +
            Contract String => Bool
         | 
| 23 | 
            +
            def from_github?(user_agent)
         | 
| 24 | 
            +
              user_agent.start_with? 'Github-Hookshot'
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            Contract String => Bool
         | 
| 28 | 
            +
            def from_bitbucket?(user_agent)
         | 
| 29 | 
            +
              user_agent.start_with? 'Bitbucket.org'
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            Contract Hash => String
         | 
| 33 | 
            +
            def detect_format_of(request)
         | 
| 34 | 
            +
              return 'empty' if request['payload'].empty?
         | 
| 35 | 
            +
              return 'Github' if from_github? request['user_agent']
         | 
| 36 | 
            +
              return 'Bitbucket' if from_bitbucket? request['user_agent']
         | 
| 37 | 
            +
              return 'JSON' if json? request['payload']
         | 
| 38 | 
            +
              'unsupported'
         | 
| 39 | 
            +
            end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            Contract String, String => Or[Hash, nil]
         | 
| 42 | 
            +
            def payload_hash_from(payload, format)
         | 
| 43 | 
            +
              lib_file = "#{__dir__}/../lib/sweatshop/payload/#{format}.rb"
         | 
| 44 | 
            +
              return nil unless File.file?(lib_file)
         | 
| 45 | 
            +
              require_relative lib_file
         | 
| 46 | 
            +
              Object.const_get("#{format}Payload").new(payload).to_hash
         | 
| 47 | 
            +
            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            Contract Hash => Hash
         | 
| 50 | 
            +
            def parse(request)
         | 
| 51 | 
            +
              format = detect_format_of request
         | 
| 52 | 
            +
              payload = payload_hash_from request['payload'], format
         | 
| 53 | 
            +
              return {payload: {}, error: "Can't parse #{format} payload"} if payload.nil?
         | 
| 54 | 
            +
              {payload: payload, error: ''}
         | 
| 55 | 
            +
            end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            Contract Any => Hash
         | 
| 58 | 
            +
            def validate(request)
         | 
| 59 | 
            +
              return {payload: {}, error: "Invalid JSON request"} unless json? request
         | 
| 60 | 
            +
              request = JSON.load request
         | 
| 61 | 
            +
              return {payload: {}, error: "Empty request"} if request.nil?
         | 
| 62 | 
            +
              request
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            puts 'Started'
         | 
| 66 | 
            +
            server = EZMQ::Server.new port: configatron.payload_parser_port#, encode: -> m { JSON.dump m }
         | 
| 67 | 
            +
            server.listen do |request|
         | 
| 68 | 
            +
              puts "Parsing: #{request}"
         | 
| 69 | 
            +
              request = validate request
         | 
| 70 | 
            +
              request = parse request unless request[:error]
         | 
| 71 | 
            +
              JSON.dump request
         | 
| 23 72 | 
             
            end
         | 
    
        data/config.defaults.yaml
    CHANGED
    
    
| @@ -1,7 +1,8 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            # http://www.url-encode-decode.com/
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 3 | 
            +
            empty: ''
         | 
| 4 | 
            +
            nonjson: not json
         | 
| 5 | 
            +
            json: '{"test1": "value", "test2": "value"}'
         | 
| 5 6 | 
             
            bitbucket: |
         | 
| 6 7 | 
             
              payload=%7B%22repository%22%3A+%7B%22website%22%3A+%22%22%2C+%22fork%22%3A+false%2C+%22name%22%3A+%22Project+X%22%2C+%22scm%22%3A+%22git%22%2C+%22owner%22%3A+%22marcus%22%2C+%22absolute_url%22%3A+%22%2Fmarcus%2Fproject-x%2F%22%2C+%22slug%22%3A+%22project-x%22%2C+%22is_private%22%3A+true%7D%2C+%22truncated%22%3A+false%2C+%22commits%22%3A+%5B%7B%22node%22%3A+%22620ade18607a%22%2C+%22files%22%3A+%5B%7B%22type%22%3A+%22modified%22%2C+%22file%22%3A+%22README%22%7D%5D%2C+%22raw_author%22%3A+%22Marcus+Bertrand+%3Cmarcus%40somedomain.com%3E%22%2C+%22utctimestamp%22%3A+%222014-08-08+00%3A04%3A07%2B00%3A00%22%2C+%22author%22%3A+%22marcus%22%2C+%22timestamp%22%3A+%222014-08-08+02%3A04%3A07%22%2C+%22raw_node%22%3A+%22620ade18607ac42d872b568bb92acaa9a28620e9%22%2C+%22parents%22%3A+%5B%22702c70160afc%22%5D%2C+%22branch%22%3A+%22develop%22%2C+%22message%22%3A+%22Added+some+more+things+to+somefile.py%5Cn%22%2C+%22revision%22%3A+null%2C+%22size%22%3A+-1%7D%5D%2C+%22canon_url%22%3A+%22https%3A%2F%2Fbitbucket.org%22%2C+%22user%22%3A+%22marcus%22%7D
         | 
| 7 8 | 
             
            github: |
         | 
    
        data/kintama/data/test_job.yaml
    CHANGED
    
    
    
        data/kintama/end-to-end_spec.rb
    CHANGED
    
    | @@ -11,18 +11,15 @@ describe 'Robot Sweatshop' do | |
| 11 11 |  | 
| 12 12 | 
             
              setup do
         | 
| 13 13 | 
             
                @client = EZMQ::Client.new port: 5556
         | 
| 14 | 
            -
                @job_name = 'test_job'
         | 
| 15 14 | 
             
                @test_file = reset_test_file
         | 
| 16 15 | 
             
                clear_all_queues
         | 
| 17 16 | 
             
              end
         | 
| 18 17 |  | 
| 19 18 | 
             
              context "POST git data to the HTTP Input" do
         | 
| 20 19 | 
             
                setup do
         | 
| 21 | 
            -
                  url = input_http_url for_job:  | 
| 22 | 
            -
             | 
| 23 | 
            -
                   | 
| 24 | 
            -
            puts "post successful"
         | 
| 25 | 
            -
                  sleep $for_everything
         | 
| 20 | 
            +
                  url = input_http_url for_job: 'test_job'
         | 
| 21 | 
            +
                  HTTP.post url, body: example_raw_payload(of_format: 'JSON')
         | 
| 22 | 
            +
                  sleep $for_io_calls
         | 
| 26 23 | 
             
                end
         | 
| 27 24 |  | 
| 28 25 | 
             
                should 'run jobs with the context as environment variables' do
         | 
    
        data/kintama/input_http_spec.rb
    CHANGED
    
    | @@ -13,32 +13,36 @@ given 'the HTTP Input' do | |
| 13 13 | 
             
              setup do
         | 
| 14 14 | 
             
                @subscriber = EZMQ::Subscriber.new port: 5557, topic: 'busy-queues'
         | 
| 15 15 | 
             
                @client = EZMQ::Client.new port: 5556
         | 
| 16 | 
            -
                @ | 
| 17 | 
            -
                @raw_payload_queue = 'raw-payload'
         | 
| 16 | 
            +
                @payload_queue = 'payload'
         | 
| 18 17 | 
             
                clear_all_queues
         | 
| 19 18 | 
             
              end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              %w(Bitbucket).each do | | 
| 22 | 
            -
                context " | 
| 19 | 
            +
             | 
| 20 | 
            +
              %w(Bitbucket Github JSON).each do |format|
         | 
| 21 | 
            +
                context "POSTing #{format} data" do
         | 
| 23 22 | 
             
                  setup do
         | 
| 24 | 
            -
                    url = input_http_url for_job:  | 
| 25 | 
            -
                    HTTP.post url, body:  | 
| 23 | 
            +
                    url = input_http_url for_job: 'test_job'
         | 
| 24 | 
            +
                    HTTP.post url, body: example_raw_payload(of_format: format)
         | 
| 26 25 | 
             
                  end
         | 
| 27 26 |  | 
| 28 | 
            -
                  should 'enqueue to \' | 
| 27 | 
            +
                  should 'enqueue to \'payload\'' do
         | 
| 29 28 | 
             
                    Timeout.timeout($for_a_moment) do
         | 
| 30 29 | 
             
                      @subscriber.listen do |message, topic|
         | 
| 31 | 
            -
                        break if message == @ | 
| 30 | 
            +
                        break if message == @payload_queue
         | 
| 32 31 | 
             
                      end
         | 
| 33 32 | 
             
                    end
         | 
| 34 33 | 
             
                  end
         | 
| 35 34 |  | 
| 36 | 
            -
                  should 'enqueue payload details' do
         | 
| 37 | 
            -
                    response = @client.request "mirror-#{@ | 
| 35 | 
            +
                  should 'enqueue payload details and format' do
         | 
| 36 | 
            +
                    response = @client.request "mirror-#{@payload_queue}"
         | 
| 38 37 | 
             
                    data = JSON.parse response
         | 
| 39 | 
            -
                     | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 38 | 
            +
                    assert_kind_of String, data['payload']
         | 
| 39 | 
            +
                    assert_kind_of String, data['user_agent']
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  should 'enqueue job name' do
         | 
| 43 | 
            +
                    response = @client.request "mirror-#{@payload_queue}"
         | 
| 44 | 
            +
                    data = JSON.parse response
         | 
| 45 | 
            +
                    assert_kind_of String, data['job_name']
         | 
| 42 46 | 
             
                  end
         | 
| 43 47 | 
             
                end
         | 
| 44 48 | 
             
              end
         | 
| @@ -6,73 +6,73 @@ require_relative 'shared/helpers' | |
| 6 6 |  | 
| 7 7 | 
             
            describe 'the Job Assembler' do
         | 
| 8 8 | 
             
              include QueueHelper
         | 
| 9 | 
            -
              include  | 
| 9 | 
            +
              include InHelper
         | 
| 10 10 | 
             
              include JobHelper
         | 
| 11 11 |  | 
| 12 12 | 
             
              setup do
         | 
| 13 13 | 
             
                @client = EZMQ::Client.new port: 5556
         | 
| 14 | 
            -
                @ | 
| 14 | 
            +
                @payloads_queue = 'payload'
         | 
| 15 15 | 
             
                @jobs_queue = 'jobs'
         | 
| 16 16 | 
             
                clear_all_queues
         | 
| 17 17 | 
             
              end
         | 
| 18 18 |  | 
| 19 | 
            -
               | 
| 20 | 
            -
                 | 
| 21 | 
            -
                   | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 19 | 
            +
              %w(Git JSON).each do |request|
         | 
| 20 | 
            +
                given "#{request} requests in \'payload\'" do
         | 
| 21 | 
            +
                  setup do
         | 
| 22 | 
            +
                    payload = example_job_request of_type: request
         | 
| 23 | 
            +
                    @client.request "#{@payloads_queue} #{payload}"
         | 
| 24 | 
            +
                    sleep $for_a_moment
         | 
| 25 | 
            +
                  end
         | 
| 25 26 |  | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 27 | 
            +
                  should 'remove the request from \'payload\'' do
         | 
| 28 | 
            +
                    response = @client.request @payloads_queue
         | 
| 29 | 
            +
                    assert_equal '', response
         | 
| 30 | 
            +
                  end
         | 
| 30 31 |  | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 32 | 
            +
                  should 'enqueue commands, context, and job name to \'jobs\'' do
         | 
| 33 | 
            +
                    response = @client.request "mirror-#{@jobs_queue}"
         | 
| 34 | 
            +
                    response = JSON.load response
         | 
| 35 | 
            +
                    assert_kind_of Hash, response['context']
         | 
| 36 | 
            +
                    assert_kind_of Array, response['commands']
         | 
| 37 | 
            +
                    assert_kind_of String, response['job_name']
         | 
| 38 | 
            +
                  end
         | 
| 38 39 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 40 | 
            +
                  should 'store everything in the context as strings' do
         | 
| 41 | 
            +
                    response = @client.request "mirror-#{@jobs_queue}"
         | 
| 42 | 
            +
                    response = JSON.load response
         | 
| 43 | 
            +
                    response['context'].each { |_key, value| assert_kind_of String, value }
         | 
| 44 | 
            +
                  end
         | 
| 44 45 |  | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
                     | 
| 46 | 
            +
                  should 'build the context with a parsed payload' do
         | 
| 47 | 
            +
                    response = @client.request "mirror-#{@jobs_queue}"
         | 
| 48 | 
            +
                    response = JSON.load response
         | 
| 49 | 
            +
                    assert_kind_of Hash, response['context']
         | 
| 50 | 
            +
                    if request == 'Git'
         | 
| 51 | 
            +
                      assert_equal 'develop', response['context']['branch']
         | 
| 52 | 
            +
                    else
         | 
| 53 | 
            +
                      assert_equal 'value', response['context']['test1']
         | 
| 54 | 
            +
                    end
         | 
| 50 55 | 
             
                  end
         | 
| 51 56 | 
             
                end
         | 
| 52 57 | 
             
              end
         | 
| 53 58 |  | 
| 54 | 
            -
               | 
| 55 | 
            -
                 | 
| 56 | 
            -
                   | 
| 57 | 
            -
                     | 
| 58 | 
            -
                     | 
| 59 | 
            -
                     | 
| 60 | 
            -
                    not_json:       'not_json'
         | 
| 61 | 
            -
                  }
         | 
| 62 | 
            -
                  invalid_data.each do |_type, datum|
         | 
| 63 | 
            -
                    @client.request "#{@parsed_payloads_queue} #{datum}"
         | 
| 59 | 
            +
              %w(IgnoredBranch UnknownJob NonJSON).each do |request|
         | 
| 60 | 
            +
                given "#{request} requests in \'payload\'" do
         | 
| 61 | 
            +
                  setup do
         | 
| 62 | 
            +
                    payload = example_job_request of_type: request
         | 
| 63 | 
            +
                    @client.request "#{@payloads_queue} #{payload}"
         | 
| 64 | 
            +
                    sleep $for_a_moment
         | 
| 64 65 | 
             
                  end
         | 
| 65 | 
            -
                  sleep $for_a_while
         | 
| 66 | 
            -
                end
         | 
| 67 66 |  | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 67 | 
            +
                  should 'remove the request from \'payload\'' do
         | 
| 68 | 
            +
                    response = @client.request @payloads_queue
         | 
| 69 | 
            +
                    assert_equal '', response
         | 
| 70 | 
            +
                  end
         | 
| 72 71 |  | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 72 | 
            +
                  should 'not queue anything to \'jobs\'' do
         | 
| 73 | 
            +
                    response = @client.request @jobs_queue
         | 
| 74 | 
            +
                    assert_equal '', response
         | 
| 75 | 
            +
                  end
         | 
| 76 76 | 
             
                end
         | 
| 77 77 | 
             
              end
         | 
| 78 78 | 
             
            end
         | 
| @@ -1,70 +1,61 @@ | |
| 1 1 | 
             
            require 'kintama'
         | 
| 2 2 | 
             
            require 'ezmq'
         | 
| 3 3 | 
             
            require 'json'
         | 
| 4 | 
            +
            require 'timeout'
         | 
| 4 5 | 
             
            require_relative 'shared/process_spawning'
         | 
| 5 6 | 
             
            require_relative 'shared/helpers'
         | 
| 6 7 |  | 
| 7 8 | 
             
            describe 'the Payload Parser' do
         | 
| 8 9 | 
             
              include QueueHelper
         | 
| 9 10 | 
             
              include InHelper
         | 
| 10 | 
            -
              include PayloadHelper
         | 
| 11 11 |  | 
| 12 12 | 
             
              setup do
         | 
| 13 | 
            -
                @client = EZMQ::Client.new port:  | 
| 14 | 
            -
                @raw_queue = 'raw-payload'
         | 
| 15 | 
            -
                @parsed_queue = 'parsed-payload'
         | 
| 16 | 
            -
                clear_all_queues
         | 
| 13 | 
            +
                @client = EZMQ::Client.new port: configatron.payload_parser_port
         | 
| 17 14 | 
             
              end
         | 
| 18 15 |  | 
| 19 | 
            -
              %w(Bitbucket Github).each do |format|
         | 
| 20 | 
            -
                given "valid #{format}  | 
| 16 | 
            +
              %w(Bitbucket Github JSON).each do |format|
         | 
| 17 | 
            +
                given "valid #{format} payloads" do
         | 
| 21 18 | 
             
                  setup do
         | 
| 22 | 
            -
                    payload =  | 
| 23 | 
            -
                    @ | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                  should 'remove it from \'raw-payload\'' do
         | 
| 28 | 
            -
                    response = @client.request @raw_queue
         | 
| 29 | 
            -
                    assert_equal '', response
         | 
| 19 | 
            +
                    payload = example_payload_request of_format: format
         | 
| 20 | 
            +
                    @response = Timeout.timeout($for_a_while) do
         | 
| 21 | 
            +
                      @client.request JSON.dump(payload)
         | 
| 22 | 
            +
                    end
         | 
| 30 23 | 
             
                  end
         | 
| 31 24 |  | 
| 32 | 
            -
                  should ' | 
| 33 | 
            -
                    response =  | 
| 34 | 
            -
                     | 
| 25 | 
            +
                  should 'return a parsed payload object' do
         | 
| 26 | 
            +
                    @response = JSON.parse @response
         | 
| 27 | 
            +
                    assert_equal true, @response['error'].empty?
         | 
| 28 | 
            +
                    assert_kind_of Hash, @response['payload']
         | 
| 35 29 |  | 
| 36 | 
            -
                     | 
| 37 | 
            -
                     | 
| 38 | 
            -
                       | 
| 39 | 
            -
             | 
| 30 | 
            +
                    keys = case format
         | 
| 31 | 
            +
                    when 'JSON'
         | 
| 32 | 
            +
                      %w(test1 test2)
         | 
| 33 | 
            +
                    else
         | 
| 34 | 
            +
                      Payload.hash_keys
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                    keys.each do |key|
         | 
| 37 | 
            +
                      payload = @response['payload']
         | 
| 38 | 
            +
                      assert_not_nil payload[key]
         | 
| 39 | 
            +
                      assert_not_equal key, payload[key] # catches "string"[key]
         | 
| 40 40 | 
             
                    end
         | 
| 41 | 
            -
                    assert_kind_of String, response['job_name']
         | 
| 42 41 | 
             
                  end
         | 
| 43 42 | 
             
                end
         | 
| 44 43 | 
             
              end
         | 
| 45 44 |  | 
| 46 | 
            -
               | 
| 47 | 
            -
                 | 
| 48 | 
            -
                   | 
| 49 | 
            -
                     | 
| 50 | 
            -
                     | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
                  invalid_data.each do |_type, datum|
         | 
| 54 | 
            -
                    @client.request "#{@raw_queue} #{datum}"
         | 
| 45 | 
            +
              %w(Empty NonJSON).each do |format|
         | 
| 46 | 
            +
                given "#{format} payloads" do
         | 
| 47 | 
            +
                  setup do
         | 
| 48 | 
            +
                    payload = example_raw_payload of_format: format
         | 
| 49 | 
            +
                    @response = Timeout.timeout($for_a_while) do
         | 
| 50 | 
            +
                      @client.request "#{payload}"
         | 
| 51 | 
            +
                    end
         | 
| 55 52 | 
             
                  end
         | 
| 56 | 
            -
                  sleep $for_a_while
         | 
| 57 | 
            -
                  # TODO: should not crash the payload parser
         | 
| 58 | 
            -
                end
         | 
| 59 53 |  | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
                should 'not queue anything to \'parsed-payload\'' do
         | 
| 66 | 
            -
                  response = @client.request @parsed_queue
         | 
| 67 | 
            -
                  assert_equal '', response
         | 
| 54 | 
            +
                  should 'return an error object' do
         | 
| 55 | 
            +
                    @response = JSON.load(@response)
         | 
| 56 | 
            +
                    assert_kind_of String, @response['error']
         | 
| 57 | 
            +
                    assert_equal true, @response['payload'].empty?
         | 
| 58 | 
            +
                  end
         | 
| 68 59 | 
             
                end
         | 
| 69 60 | 
             
              end
         | 
| 70 61 | 
             
            end
         | 
    
        data/kintama/shared/helpers.rb
    CHANGED
    
    | @@ -1,8 +1,9 @@ | |
| 1 | 
            +
            require 'bundler/setup'
         | 
| 1 2 | 
             
            require 'yaml'
         | 
| 2 3 | 
             
            require 'json'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 4 | 
            +
            require 'sweatshop/moneta-queue'
         | 
| 5 | 
            +
            require 'sweatshop/payload'
         | 
| 6 | 
            +
            require 'sweatshop/config'
         | 
| 6 7 |  | 
| 7 8 | 
             
            module QueueHelper
         | 
| 8 9 | 
             
              def clear_all_queues
         | 
| @@ -18,26 +19,50 @@ module QueueHelper | |
| 18 19 | 
             
            end
         | 
| 19 20 |  | 
| 20 21 | 
             
            module InHelper
         | 
| 21 | 
            -
              def  | 
| 22 | 
            +
              def example_raw_payload(of_format:)
         | 
| 22 23 | 
             
                payload_strings = YAML.load_file "#{__dir__}/../data/payload_data.yaml"
         | 
| 23 24 | 
             
                payload_strings[of_format.downcase]
         | 
| 24 25 | 
             
              end
         | 
| 25 | 
            -
              def  | 
| 26 | 
            -
                payload | 
| 27 | 
            -
                JSON.generate payload: payload,
         | 
| 28 | 
            -
                              format: with_format,
         | 
| 29 | 
            -
                              job_name: 'test_job'
         | 
| 26 | 
            +
              def input_http_url(for_job: 'test_job')
         | 
| 27 | 
            +
                "http://localhost:#{configatron.http_port}/payload-for/#{for_job}"
         | 
| 30 28 | 
             
              end
         | 
| 31 | 
            -
              def  | 
| 32 | 
            -
                 | 
| 29 | 
            +
              def user_agent_for(format)
         | 
| 30 | 
            +
                case format
         | 
| 31 | 
            +
                when 'Bitbucket'
         | 
| 32 | 
            +
                  'Bitbucket.org'
         | 
| 33 | 
            +
                when 'Github'
         | 
| 34 | 
            +
                  'Github-Hookshot'
         | 
| 35 | 
            +
                else
         | 
| 36 | 
            +
                  'SomeRandomUserAgent'
         | 
| 37 | 
            +
                end
         | 
| 33 38 | 
             
              end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                 | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 39 | 
            +
              def example_payload_request(of_format:)
         | 
| 40 | 
            +
                {
         | 
| 41 | 
            +
                  payload: example_raw_payload(of_format: of_format),
         | 
| 42 | 
            +
                  user_agent: user_agent_for(of_format)
         | 
| 43 | 
            +
                }
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
              def job_request_data(type)
         | 
| 46 | 
            +
                case type
         | 
| 47 | 
            +
                when 'Git'
         | 
| 48 | 
            +
                  ['Bitbucket', 'git_job'] # develop branch
         | 
| 49 | 
            +
                when 'JSON'
         | 
| 50 | 
            +
                  ['JSON', 'test_job']
         | 
| 51 | 
            +
                when 'IgnoredBranch'
         | 
| 52 | 
            +
                  ['Github', 'git_job'] # master branch
         | 
| 53 | 
            +
                when 'UnknownJob'
         | 
| 54 | 
            +
                  ['Bitbucket', 'unknown_job']
         | 
| 55 | 
            +
                when 'NonJSON'
         | 
| 56 | 
            +
                  ['JSON', 'git_job', 'not json']
         | 
| 57 | 
            +
                else
         | 
| 58 | 
            +
                  ['I', 'AM', 'ERROR']
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
              def example_job_request(of_type:)
         | 
| 62 | 
            +
                format, job_name, payload = job_request_data of_type
         | 
| 63 | 
            +
                JSON.generate payload: payload || example_raw_payload(of_format: format),
         | 
| 64 | 
            +
                              job_name: job_name,
         | 
| 65 | 
            +
                              user_agent: user_agent_for(format)
         | 
| 41 66 | 
             
              end
         | 
| 42 67 | 
             
            end
         | 
| 43 68 |  | 
| @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            $for_a_moment = 0.1
         | 
| 2 2 | 
             
            $for_a_while = 0.5
         | 
| 3 3 | 
             
            $for_io_calls = 1
         | 
| 4 | 
            -
            $for_everything =  | 
| 4 | 
            +
            $for_everything = 2
         | 
| 5 5 |  | 
| 6 6 | 
             
            Kintama.on_start do
         | 
| 7 7 | 
             
              puts `#{__dir__}/../../bin/sweatshop start --testing`
         | 
| 8 8 | 
             
              FileUtils.cp "#{__dir__}/../data/test_job.yaml", File.expand_path(configatron.job_directory)
         | 
| 9 | 
            +
              FileUtils.cp "#{__dir__}/../data/git_job.yaml", File.expand_path(configatron.job_directory)
         | 
| 9 10 | 
             
              sleep $for_everything
         | 
| 10 11 | 
             
            end
         | 
| 11 12 |  | 
| 12 13 | 
             
            Kintama.on_finish do
         | 
| 13 14 | 
             
              puts `#{__dir__}/../../bin/sweatshop stop`
         | 
| 14 | 
            -
              # FileUtils.rm "#{configatron.job_directory}/test_job.yaml"
         | 
| 15 15 | 
             
            end
         | 
    
        data/lib/README.md
    CHANGED
    
    | @@ -1,8 +1,7 @@ | |
| 1 1 | 
             
            Job lifecycle:
         | 
| 2 2 |  | 
| 3 3 | 
             
            ```
         | 
| 4 | 
            -
            in-* ->  | 
| 5 | 
            -
            payload-parser -> parsed-payloads { payload:, job_name: } ->
         | 
| 4 | 
            +
            in-* -> payloads { payload:, user_agent:, job_name: } ->
         | 
| 6 5 | 
             
            job-assembler -> jobs { context:, commands:, job_name: } ->
         | 
| 7 6 | 
             
            job-worker
         | 
| 8 7 | 
             
            ```
         | 
| @@ -10,3 +9,13 @@ job-worker | |
| 10 9 | 
             
            All passing done via the moneta core in queue/*
         | 
| 11 10 |  | 
| 12 11 | 
             
            Also queue/watcher for debugging
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ---
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            The Job Assembler also uses the Payload Parser service:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ```
         | 
| 18 | 
            +
            { payload:, user_agent: } -> payload-parser -> { payload:, error: }
         | 
| 19 | 
            +
            ```
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            Error is an empty string when it's successful. Otherwise it details what went wrong.
         | 
    
        data/lib/sweatshop/cli/job.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            require_relative '../config'
         | 
| 2 2 |  | 
| 3 3 | 
             
            def default_job
         | 
| 4 | 
            -
              "---\ | 
| 4 | 
            +
              "---\n# branch_whitelist:\n# - master\n\ncommands:\n- echo \"Hello $WORLD!\"\n\nenvironment:\n  WORLD: Earth\n"
         | 
| 5 5 | 
             
            end
         | 
| 6 6 |  | 
| 7 7 | 
             
            def get_job_path(for_job: nil)
         | 
    
        data/lib/sweatshop.rb
    CHANGED
    
    | @@ -1,16 +1,5 @@ | |
| 1 1 | 
             
            require_relative 'sweatshop/moneta-queue'
         | 
| 2 2 | 
             
            require_relative 'sweatshop/queue-helper'
         | 
| 3 3 | 
             
            require_relative 'sweatshop/config'
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            require_relative 'sweatshop/ | 
| 6 | 
            -
            require_relative 'sweatshop/payload/bitbucket'
         | 
| 7 | 
            -
            require_relative 'sweatshop/payload/github'
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            require_relative 'sweatshop/cli/common'
         | 
| 10 | 
            -
            require_relative 'sweatshop/cli/config'
         | 
| 11 | 
            -
            require_relative 'sweatshop/cli/inspect'
         | 
| 12 | 
            -
            require_relative 'sweatshop/cli/job'
         | 
| 13 | 
            -
            require_relative 'sweatshop/cli/setup'
         | 
| 14 | 
            -
            require_relative 'sweatshop/cli/start'
         | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 4 | 
            +
            require_relative 'sweatshop/payload'
         | 
| 5 | 
            +
            require_relative 'sweatshop/cli'
         | 
    
        data/robot_sweatshop.gemspec
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |gem|
         | 
| 2 2 | 
             
              gem.name        = 'robot_sweatshop'
         | 
| 3 | 
            -
              gem.version     = '0. | 
| 3 | 
            +
              gem.version     = '0.3.0'
         | 
| 4 4 | 
             
              gem.licenses    = 'MIT'
         | 
| 5 5 | 
             
              gem.authors     = ['Justin Scott']
         | 
| 6 6 | 
             
              gem.email       = 'jvscott@gmail.com'
         | 
| @@ -20,9 +20,10 @@ Gem::Specification.new do |gem| | |
| 20 20 | 
             
              gem.add_runtime_dependency 'faker'
         | 
| 21 21 | 
             
              gem.add_runtime_dependency 'commander'
         | 
| 22 22 | 
             
              gem.add_runtime_dependency 'eye'
         | 
| 23 | 
            -
              gem.add_runtime_dependency 'colorize'
         | 
| 23 | 
            +
              gem.add_runtime_dependency 'colorize' # TODO: replace with rainbow
         | 
| 24 24 | 
             
              gem.add_runtime_dependency 'configatron'
         | 
| 25 25 | 
             
              gem.add_runtime_dependency 'moneta'
         | 
| 26 | 
            +
              gem.add_runtime_dependency 'contracts'
         | 
| 26 27 |  | 
| 27 28 | 
             
              gem.add_development_dependency 'rake'
         | 
| 28 29 | 
             
              gem.add_development_dependency 'kintama'
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: robot_sweatshop
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Justin Scott
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015-04- | 
| 11 | 
            +
            date: 2015-04-30 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: sinatra
         | 
| @@ -122,6 +122,20 @@ dependencies: | |
| 122 122 | 
             
                - - ">="
         | 
| 123 123 | 
             
                  - !ruby/object:Gem::Version
         | 
| 124 124 | 
             
                    version: '0'
         | 
| 125 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 126 | 
            +
              name: contracts
         | 
| 127 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 128 | 
            +
                requirements:
         | 
| 129 | 
            +
                - - ">="
         | 
| 130 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 131 | 
            +
                    version: '0'
         | 
| 132 | 
            +
              type: :runtime
         | 
| 133 | 
            +
              prerelease: false
         | 
| 134 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 135 | 
            +
                requirements:
         | 
| 136 | 
            +
                - - ">="
         | 
| 137 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 138 | 
            +
                    version: '0'
         | 
| 125 139 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 126 140 | 
             
              name: rake
         | 
| 127 141 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -236,6 +250,7 @@ files: | |
| 236 250 | 
             
            - bin/sweatshop-queue-watcher
         | 
| 237 251 | 
             
            - config.defaults.yaml
         | 
| 238 252 | 
             
            - kintama/README.md
         | 
| 253 | 
            +
            - kintama/data/git_job.yaml
         | 
| 239 254 | 
             
            - kintama/data/payload_data.yaml
         | 
| 240 255 | 
             
            - kintama/data/test_job.yaml
         | 
| 241 256 | 
             
            - kintama/end-to-end_spec.rb
         | 
| @@ -251,6 +266,7 @@ files: | |
| 251 266 | 
             
            - kintama/shared/process_spawning.rb
         | 
| 252 267 | 
             
            - lib/README.md
         | 
| 253 268 | 
             
            - lib/sweatshop.rb
         | 
| 269 | 
            +
            - lib/sweatshop/cli.rb
         | 
| 254 270 | 
             
            - lib/sweatshop/cli/common.rb
         | 
| 255 271 | 
             
            - lib/sweatshop/cli/config.rb
         | 
| 256 272 | 
             
            - lib/sweatshop/cli/job.rb
         | 
| @@ -258,8 +274,10 @@ files: | |
| 258 274 | 
             
            - lib/sweatshop/config.rb
         | 
| 259 275 | 
             
            - lib/sweatshop/create-config-directories.rb
         | 
| 260 276 | 
             
            - lib/sweatshop/moneta-queue.rb
         | 
| 277 | 
            +
            - lib/sweatshop/payload.rb
         | 
| 261 278 | 
             
            - lib/sweatshop/payload/bitbucket.rb
         | 
| 262 279 | 
             
            - lib/sweatshop/payload/github.rb
         | 
| 280 | 
            +
            - lib/sweatshop/payload/json.rb
         | 
| 263 281 | 
             
            - lib/sweatshop/payload/payload.rb
         | 
| 264 282 | 
             
            - lib/sweatshop/queue-helper.rb
         | 
| 265 283 | 
             
            - robot_sweatshop.eye
         | 
| @@ -291,6 +309,7 @@ signing_key: | |
| 291 309 | 
             
            specification_version: 4
         | 
| 292 310 | 
             
            summary: Robot Sweatshop
         | 
| 293 311 | 
             
            test_files:
         | 
| 312 | 
            +
            - kintama/data/git_job.yaml
         | 
| 294 313 | 
             
            - kintama/data/payload_data.yaml
         | 
| 295 314 | 
             
            - kintama/data/test_job.yaml
         | 
| 296 315 | 
             
            - kintama/shared/helpers.rb
         |