robot_sweatshop 0.1.6 → 0.2.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/.gitignore +4 -3
- data/README.md +14 -12
- data/Rakefile +0 -4
- data/bin/sweatshop +28 -46
- data/{lib/input/http.rb → bin/sweatshop-input-http} +4 -3
- data/{lib/job/assembler.rb → bin/sweatshop-job-assembler} +15 -23
- data/{lib/job/worker.rb → bin/sweatshop-job-worker} +6 -3
- data/{lib/payload/parser.rb → bin/sweatshop-payload-parser} +2 -2
- data/{lib/queue/broadcaster.rb → bin/sweatshop-queue-broadcaster} +2 -1
- data/{lib/queue/handler.rb → bin/sweatshop-queue-handler} +1 -1
- data/{lib/queue/watcher.rb → bin/sweatshop-queue-watcher} +0 -0
- data/config.defaults.yaml +10 -0
- data/{jobs/example.yaml → kintama/data/test_job.yaml} +0 -0
- data/kintama/end-to-end_spec.rb +1 -1
- data/kintama/input_http_spec.rb +1 -1
- data/kintama/moneta-queue_spec.rb +1 -1
- data/kintama/shared/helpers.rb +9 -9
- data/kintama/shared/process_spawning.rb +2 -0
- data/{bin/lib → lib/sweatshop/cli}/common.rb +8 -16
- data/lib/sweatshop/cli/config.rb +16 -0
- data/lib/sweatshop/cli/job.rb +14 -0
- data/lib/sweatshop/cli/start.rb +25 -0
- data/lib/sweatshop/config.rb +19 -0
- data/lib/sweatshop/create-config-directories.rb +29 -0
- data/lib/{queue/lib → sweatshop}/moneta-queue.rb +2 -2
- data/lib/{payload/lib → sweatshop/payload}/bitbucket.rb +0 -0
- data/lib/{payload/lib → sweatshop/payload}/github.rb +0 -0
- data/lib/{payload/lib → sweatshop/payload}/payload.rb +0 -0
- data/lib/{queue-helper.rb → sweatshop/queue-helper.rb} +0 -0
- data/lib/sweatshop.rb +16 -0
- data/robot_sweatshop.eye +26 -26
- data/robot_sweatshop.gemspec +5 -2
- data/robot_sweatshop.production.eye +2 -3
- data/robot_sweatshop.testing.eye +2 -3
- metadata +59 -23
- data/bin/lib/config.rb +0 -20
- data/bin/lib/inspect.rb +0 -42
- data/bin/lib/job.rb +0 -13
- data/bin/lib/setup.rb +0 -25
- data/bin/lib/start.rb +0 -11
- data/config.rb +0 -16
- data/config.yaml +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edaa6abb2f131c571be0f100430763222e988055
|
4
|
+
data.tar.gz: dd254380c37b2e7cc946d077e01f5114bf15f609
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67a7804817f3f55a23e147a5cb2f15043b34cc906c6783a4bd55dce02ce846ee7d9b442b1c51d96477c27b173dfc9ab9ea59a476b549b096bb9bce508956c6fb
|
7
|
+
data.tar.gz: d14b8909e070f2ac63346e233758f353e0345f61afe2e5f5fccf6f4afd6570024f9d8ef92ed3e1da1817f6c93e759b3a7ea4b62358d2b534f45d315c6528b298
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -4,29 +4,30 @@
|
|
4
4
|
|
5
5
|
Robot Sweatshop is a single-purpose CI server that runs collections of arbitrary scripts when it needs to, usually when new code is pushed. There's no assumptions about what you want to report, what front-end you need, or even what repositories you want to clone because you can do that better than I can. It's just you, your code, and the scripts that test and deploy it.
|
6
6
|
|
7
|
-
#
|
7
|
+
# Quick start
|
8
|
+
|
9
|
+
- install [ZMQ as described in the EZMQ gem](https://github.com/colstrom/ezmq)
|
10
|
+
- `gem install robot_sweatshop`
|
11
|
+
- `sweatshop start` ([you may need sudo on OSX](https://github.com/JScott/robot_sweatshop/wiki))
|
12
|
+
- `sweatshop job example --auto`
|
13
|
+
- POST a Github payload to `localhost:8080/github/payload-for/example`
|
14
|
+
- `cat .robot_sweatshop/log/job-worker.log`
|
8
15
|
|
9
|
-
|
16
|
+
# Usage
|
10
17
|
|
11
|
-
|
18
|
+
Drop the `--auto` flag to create the job interactively. You can specify which branches will trigger the job, which commands will be run, and any environment variables you might need.
|
12
19
|
|
13
20
|
Robot Sweatshop uses [Eye](https://github.com/kostya/eye) to handle its processes so you can use its commandline tool to monitor their status.
|
14
21
|
|
15
|
-
|
22
|
+
# Configuration
|
16
23
|
|
17
|
-
You can
|
24
|
+
By default, Robot Sweatshop looks in your current working directory to configure and run. You can supply a custom configuration with `sweatshop config [local|user|system]`. Read [the wiki](https://github.com/JScott/robot_sweatshop/wiki) for more information.
|
18
25
|
|
19
|
-
|
26
|
+
# Supported payload formats
|
20
27
|
|
21
28
|
- Github (application/json format only)
|
22
29
|
- Bitbucket
|
23
30
|
|
24
|
-
# Configuration
|
25
|
-
|
26
|
-
The server isn't much help without a job to run. Run `sweatshop job <name>` to create a new job or edit an existing one.
|
27
|
-
|
28
|
-
Not sure if your job is valid? Run `sweatshop job --inspection <name>` to see if there's something you overlooked.
|
29
|
-
|
30
31
|
# Security
|
31
32
|
|
32
33
|
You probably don't want to run Robot Sweatshop as a sudo user. Create a testing user and group and point to them in the configuration file to run Robot Sweatshop processes with those permissions.
|
@@ -38,6 +39,7 @@ You probably don't want to run Robot Sweatshop as a sudo user. Create a testing
|
|
38
39
|
- Common scrips such as git repo syncing and creating a job run ID
|
39
40
|
- Support for multiple workers
|
40
41
|
- Better logging for the processes
|
42
|
+
- Use [eye-http](https://github.com/kostya/eye-http) for the '/' route?
|
41
43
|
- Improved architecture:
|
42
44
|
|
43
45
|

|
data/Rakefile
CHANGED
data/bin/sweatshop
CHANGED
@@ -2,43 +2,52 @@
|
|
2
2
|
require 'yaml'
|
3
3
|
require 'commander/import'
|
4
4
|
require 'colorize'
|
5
|
-
require_relative 'lib/common'
|
6
|
-
require_relative 'lib/job'
|
7
|
-
require_relative 'lib/
|
8
|
-
require_relative 'lib/
|
9
|
-
require_relative 'lib/config'
|
10
|
-
require_relative '../config'
|
5
|
+
require_relative '../lib/sweatshop/cli/common'
|
6
|
+
require_relative '../lib/sweatshop/cli/job'
|
7
|
+
require_relative '../lib/sweatshop/cli/start'
|
8
|
+
require_relative '../lib/sweatshop/cli/config'
|
9
|
+
require_relative '../lib/sweatshop/config'
|
10
|
+
require_relative '../lib/sweatshop/create-config-directories'
|
11
11
|
|
12
12
|
program :name, 'Robot Sweatshop'
|
13
|
-
program :version, '0.
|
13
|
+
program :version, '0.2.0'
|
14
14
|
program :description, 'A lightweight, unopinionated CI server'
|
15
15
|
program :help, 'Author', 'Justin Scott <jvscott@gmail.com>'
|
16
16
|
|
17
17
|
command :job do |c|
|
18
18
|
c.syntax = 'sweatshop job <name>'
|
19
19
|
c.description = 'Creates and edits jobs.'
|
20
|
-
c.option '--
|
21
|
-
c.option '--inspection', 'Inspect the given job.'
|
20
|
+
c.option '--auto', 'Create the file without opening the editor.'
|
22
21
|
c.action do |args, options|
|
23
|
-
options.default :
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
if options.list
|
28
|
-
list_jobs
|
29
|
-
elsif options.inspection
|
30
|
-
validate job_file unless job_file.nil?
|
22
|
+
options.default :auto => false
|
23
|
+
if args.count < 1
|
24
|
+
notify :failure, "Specify a job name as the command argument."
|
25
|
+
exit 1
|
31
26
|
else
|
32
|
-
|
27
|
+
job_file = get_job_path for_job: args.first
|
28
|
+
create job_file, with_contents: default_job
|
29
|
+
edit job_file unless options.auto
|
33
30
|
end
|
34
31
|
end
|
35
32
|
end
|
36
33
|
|
34
|
+
command :config do |c|
|
35
|
+
c.syntax = 'sweatshop config [options]'
|
36
|
+
c.description = 'Creates and edits the user configuration file.'
|
37
|
+
c.option '--auto', 'Create the file without opening the editor.'
|
38
|
+
c.action do |args, options|
|
39
|
+
options.default :auto => false
|
40
|
+
config_file = get_config_path for_scope: args.first
|
41
|
+
create config_file, with_contents: default_config
|
42
|
+
edit config_file unless options.auto
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
37
46
|
command :start do |c|
|
38
47
|
c.syntax = 'sweatshop start [options]'
|
39
48
|
c.description = 'Start the Sweatshop.'
|
40
49
|
c.option '--testing', 'Load the testing Eye configuration.'
|
41
|
-
c.action do |
|
50
|
+
c.action do |_args, options|
|
42
51
|
options.default :testing => false
|
43
52
|
environment = options.testing ? 'testing' : 'production'
|
44
53
|
start_sweatshop for_environment: environment
|
@@ -52,30 +61,3 @@ command :stop do |c|
|
|
52
61
|
notify :info, `eye stop robot_sweatshop`
|
53
62
|
end
|
54
63
|
end
|
55
|
-
|
56
|
-
command :setup do |c|
|
57
|
-
c.syntax = 'sweatshop setup'
|
58
|
-
c.description = 'Create the directories and set permissions as specified in the config.'
|
59
|
-
c.action do
|
60
|
-
require_relative 'lib/setup'
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
command :directory do |c|
|
65
|
-
c.syntax = 'sweatshop directory'
|
66
|
-
c.description = 'Return the path that Robot Sweatshop runs from.'
|
67
|
-
c.action do
|
68
|
-
puts File.expand_path("#{__dir__}/..")
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
command :config do |c|
|
73
|
-
c.syntax = 'sweatshop config [options]'
|
74
|
-
c.description = 'Creates and edits the user configuration file.'
|
75
|
-
c.option '--reset', 'Reset to factory defaults before editing.'
|
76
|
-
c.action do |args, options|
|
77
|
-
options.default :reset => false
|
78
|
-
remove_user_config if options.reset
|
79
|
-
create_and_edit_user_config
|
80
|
-
end
|
81
|
-
end
|
@@ -2,12 +2,13 @@
|
|
2
2
|
require 'sinatra'
|
3
3
|
require 'ezmq'
|
4
4
|
require 'json'
|
5
|
-
require_relative '
|
5
|
+
require_relative '../lib/sweatshop/config'
|
6
6
|
|
7
7
|
configure do
|
8
|
-
set :port, configatron.
|
9
|
-
set :bind, configatron.
|
8
|
+
set :port, configatron.http_port
|
9
|
+
set :bind, configatron.http_bind
|
10
10
|
set :output_queue, 'raw-payload'
|
11
|
+
set :run, true
|
11
12
|
end
|
12
13
|
|
13
14
|
get '/' do
|
@@ -1,28 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'yaml'
|
3
|
-
require_relative '../queue-helper'
|
4
|
-
require_relative '
|
3
|
+
require_relative '../lib/sweatshop/queue-helper'
|
4
|
+
require_relative '../lib/sweatshop/config'
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
puts
|
14
|
-
|
15
|
-
end
|
16
|
-
nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def load_config(for_job_name:)
|
20
|
-
job_config_path = find_job_config_file for_job_name
|
21
|
-
if job_config_path.nil?
|
22
|
-
puts "No config found for job '#{for_job_name}'"
|
23
|
-
return nil
|
6
|
+
def load_config(for_job:)
|
7
|
+
job_directory = File.expand_path configatron.job_directory
|
8
|
+
file_path = "#{job_directory}/#{for_job}.yaml"
|
9
|
+
puts file_path
|
10
|
+
if File.file?(file_path)
|
11
|
+
YAML.load_file file_path
|
12
|
+
else
|
13
|
+
puts "No config found for job '#{for_job}'"
|
14
|
+
nil
|
24
15
|
end
|
25
|
-
YAML.load_file job_config_path
|
26
16
|
end
|
27
17
|
|
28
18
|
def serialize(value)
|
@@ -30,8 +20,8 @@ def serialize(value)
|
|
30
20
|
end
|
31
21
|
|
32
22
|
def assemble_job(data)
|
33
|
-
job_config = load_config
|
34
|
-
return nil
|
23
|
+
job_config = load_config for_job: data['job_name']
|
24
|
+
return nil if job_config.nil?
|
35
25
|
if job_config['branch_whitelist'].include? data['payload']['branch']
|
36
26
|
context = job_config['environment'].merge(data['payload'])
|
37
27
|
context.each { |key, value| context[key] = serialize value }
|
@@ -50,4 +40,6 @@ QueueHelper.wait_for('parsed-payload') do |data|
|
|
50
40
|
puts "Assembling: #{data}"
|
51
41
|
assembled_job = assemble_job data
|
52
42
|
QueueHelper.enqueue assembled_job, to: 'jobs' if assembled_job
|
43
|
+
$stdout.flush
|
44
|
+
$stderr.flush
|
53
45
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'faker'
|
3
3
|
require 'fileutils'
|
4
|
-
require_relative '../queue-helper'
|
5
|
-
require_relative '
|
4
|
+
require_relative '../lib/sweatshop/queue-helper'
|
5
|
+
require_relative '../lib/sweatshop/config'
|
6
|
+
|
7
|
+
$stdout.sync = true
|
8
|
+
$stderr.sync = true
|
6
9
|
|
7
10
|
# TODO: check existing worker ids. it'd be disastrous to have two sharing a workspace
|
8
11
|
@worker_id = ARGV[0] || "#{Faker::Name.first_name}"
|
@@ -10,7 +13,7 @@ require_relative '../../config'
|
|
10
13
|
def from_workspace(named: 'no_job_name')
|
11
14
|
workspace = "#{named}-#{@worker_id}"
|
12
15
|
puts "Workspace: #{workspace}"
|
13
|
-
path = "#{configatron.
|
16
|
+
path = File.expand_path "#{configatron.workspace_directory}/#{workspace}"
|
14
17
|
FileUtils.mkpath path
|
15
18
|
Dir.chdir(path) { yield if block_given? }
|
16
19
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require_relative '../queue-helper'
|
2
|
+
require_relative '../lib/sweatshop/queue-helper'
|
3
3
|
|
4
4
|
def parse(payload = '', of_format:)
|
5
5
|
of_format = of_format.downcase
|
6
|
-
lib_file = "#{__dir__}/
|
6
|
+
lib_file = "#{__dir__}/../lib/sweatshop/payload/#{of_format}.rb"
|
7
7
|
if of_format != 'payload' && File.file?(lib_file)
|
8
8
|
require_relative lib_file
|
9
9
|
Object.const_get("#{of_format.capitalize}Payload").new payload
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require_relative 'lib/moneta-queue'
|
2
|
+
require_relative '../lib/sweatshop/moneta-queue'
|
3
3
|
require 'ezmq'
|
4
4
|
|
5
5
|
publisher = EZMQ::Publisher.new port: 5557
|
@@ -12,6 +12,7 @@ end
|
|
12
12
|
|
13
13
|
loop do
|
14
14
|
queues.each do |queue_name, queue|
|
15
|
+
p queue_name if queue.size > 0
|
15
16
|
publisher.send queue_name, topic: 'busy-queues' if queue.size > 0
|
16
17
|
end
|
17
18
|
sleep @wait_time unless @wait_time == 0
|
File without changes
|
@@ -0,0 +1,10 @@
|
|
1
|
+
---
|
2
|
+
pidfile_directory: .robot_sweatshop/run
|
3
|
+
logfile_directory: .robot_sweatshop/log
|
4
|
+
job_directory: .robot_sweatshop/jobs
|
5
|
+
workspace_directory: .robot_sweatshop/workspaces
|
6
|
+
moneta_directory: .robot_sweatshop/db
|
7
|
+
# user: ci-bot
|
8
|
+
# group: nogroup
|
9
|
+
http_port: 8080
|
10
|
+
http_bind: 0.0.0.0
|
File without changes
|
data/kintama/end-to-end_spec.rb
CHANGED
data/kintama/input_http_spec.rb
CHANGED
@@ -13,7 +13,7 @@ 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
|
-
@job_name = '
|
16
|
+
@job_name = 'test_job'
|
17
17
|
@raw_payload_queue = 'raw-payload'
|
18
18
|
clear_all_queues
|
19
19
|
end
|
data/kintama/shared/helpers.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'json'
|
3
|
-
require_relative '../../lib/
|
4
|
-
require_relative '../../lib/payload/
|
5
|
-
require_relative '../../config'
|
3
|
+
require_relative '../../lib/sweatshop/moneta-queue'
|
4
|
+
require_relative '../../lib/sweatshop/payload/payload'
|
5
|
+
require_relative '../../lib/sweatshop/config'
|
6
6
|
|
7
7
|
module QueueHelper
|
8
8
|
def clear_all_queues
|
@@ -26,15 +26,15 @@ module InHelper
|
|
26
26
|
payload = load_payload with_format
|
27
27
|
JSON.generate payload: payload,
|
28
28
|
format: with_format,
|
29
|
-
job_name: '
|
29
|
+
job_name: 'test_job'
|
30
30
|
end
|
31
|
-
def input_http_url(for_job: '
|
32
|
-
"http://localhost:#{configatron.
|
31
|
+
def input_http_url(for_job: 'test_job', in_format: 'bitbucket')
|
32
|
+
"http://localhost:#{configatron.http_port}/#{in_format}/payload-for/#{for_job}"
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
module PayloadHelper
|
37
|
-
def example_parsed_payload(with_payload: nil, for_branch: 'develop', for_job: '
|
37
|
+
def example_parsed_payload(with_payload: nil, for_branch: 'develop', for_job: 'test_job')
|
38
38
|
payload = with_payload || { branch: for_branch }
|
39
39
|
JSON.generate payload: payload,
|
40
40
|
job_name: for_job
|
@@ -45,10 +45,10 @@ module JobHelper
|
|
45
45
|
def example_job(in_context: {}, with_commands: [])
|
46
46
|
JSON.generate context: in_context,
|
47
47
|
commands: with_commands,
|
48
|
-
job_name: '
|
48
|
+
job_name: 'test_job'
|
49
49
|
end
|
50
50
|
def reset_test_file
|
51
|
-
test_file = File.expand_path "#{configatron.
|
51
|
+
test_file = File.expand_path "#{configatron.workspace_directory}/test_job-testingid/test.txt"
|
52
52
|
FileUtils.rm_rf test_file
|
53
53
|
test_file
|
54
54
|
end
|
@@ -5,9 +5,11 @@ $for_everything = 3
|
|
5
5
|
|
6
6
|
Kintama.on_start do
|
7
7
|
puts `#{__dir__}/../../bin/sweatshop start --testing`
|
8
|
+
FileUtils.cp "#{__dir__}/../data/test_job.yaml", File.expand_path(configatron.job_directory)
|
8
9
|
sleep $for_everything
|
9
10
|
end
|
10
11
|
|
11
12
|
Kintama.on_finish do
|
12
13
|
puts `#{__dir__}/../../bin/sweatshop stop`
|
14
|
+
# FileUtils.rm "#{configatron.job_directory}/test_job.yaml"
|
13
15
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require_relative '../config'
|
2
3
|
|
3
4
|
def notify(type = :success, string)
|
4
5
|
color = case type
|
@@ -16,34 +17,25 @@ def notify(type = :success, string)
|
|
16
17
|
puts "[#{type.to_s.capitalize.colorize(color)}] #{string}"
|
17
18
|
end
|
18
19
|
|
19
|
-
def get_job_file(for_job:)
|
20
|
-
for_job = "#{__dir__}/../../jobs/#{for_job}.yaml"
|
21
|
-
if for_job.nil?
|
22
|
-
notify :failure, 'Please specify the job to create or edit. See --help for details'
|
23
|
-
nil
|
24
|
-
else
|
25
|
-
File.expand_path for_job
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
20
|
def edit(file)
|
30
21
|
edit = ENV['EDITOR']
|
31
22
|
if edit
|
32
23
|
notify :info, "Manually editing file '#{file}'"
|
33
24
|
system edit, file
|
34
25
|
else
|
35
|
-
notify :
|
26
|
+
notify :warning, "No editor specified in $EDITOR environment variable"
|
36
27
|
notify :info, "Displaying file contents instead"
|
37
28
|
system 'cat', file
|
38
29
|
end
|
39
30
|
end
|
40
31
|
|
41
|
-
def
|
32
|
+
def create(file, with_contents: '')
|
42
33
|
file = File.expand_path file
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
if File.file?(file)
|
35
|
+
notify :info, "'#{file}' already exists"
|
36
|
+
else
|
37
|
+
FileUtils.mkdir_p File.dirname(file)
|
38
|
+
File.write file, with_contents
|
46
39
|
notify :success, "Created new file '#{file}'"
|
47
40
|
end
|
48
|
-
edit file
|
49
41
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../config'
|
2
|
+
|
3
|
+
def default_config
|
4
|
+
File.read "#{__dir__}/../../../config.defaults.yaml"
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_config_path(for_scope: 'local')
|
8
|
+
case for_scope
|
9
|
+
when 'system'
|
10
|
+
"/etc/robot_sweatshop/config.yaml"
|
11
|
+
when 'user'
|
12
|
+
"~/.robot_sweatshop/config.yaml"
|
13
|
+
else
|
14
|
+
".robot_sweatshop/config.yaml"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../config'
|
2
|
+
|
3
|
+
def default_job
|
4
|
+
"---\nbranch_whitelist:\n- master\n\ncommands:\n- echo 'Hello $WORLD!'\n\nenvironment:\n WORLD: Earth\n"
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_job_path(for_job: nil)
|
8
|
+
"#{configatron.job_directory}/#{for_job}.yaml"
|
9
|
+
end
|
10
|
+
|
11
|
+
def list_jobs
|
12
|
+
job_directory = File.expand_path configatron.job_directory
|
13
|
+
puts Dir.glob("#{job_directory}/*.yaml").map { |file| File.basename(file, '.yaml') }
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative '../config'
|
3
|
+
|
4
|
+
def store_config_for_eye
|
5
|
+
config = configatron.to_h
|
6
|
+
config = config.each do |key, value|
|
7
|
+
config[key] = File.expand_path value if key.to_s.match /_directory/
|
8
|
+
end
|
9
|
+
config[:working_directory] = Dir.pwd
|
10
|
+
File.write('/tmp/.robot_sweatshop-eye-config.yaml', config.to_yaml)
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_sweatshop(for_environment:)
|
14
|
+
store_config_for_eye
|
15
|
+
eye_config = File.expand_path "#{__dir__}/../../../robot_sweatshop.#{for_environment}.eye"
|
16
|
+
output = `eye load #{eye_config}`
|
17
|
+
if $?.exitstatus != 0
|
18
|
+
notify :failure, output
|
19
|
+
exit 1
|
20
|
+
else
|
21
|
+
notify :success, "Robot Sweatshop loaded with a #{for_environment} configuration"
|
22
|
+
notify :info, `eye restart robot_sweatshop`
|
23
|
+
notify :info, 'Run \'eye --help\' for more info on debugging'
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'configatron'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
configatron.reset!
|
5
|
+
|
6
|
+
configurations = [
|
7
|
+
"#{__dir__}/../../config.defaults.yaml",
|
8
|
+
"/etc/robot_sweatshop/config.yaml",
|
9
|
+
"~/.robot_sweatshop/config.yaml",
|
10
|
+
".robot_sweatshop/config.yaml",
|
11
|
+
]
|
12
|
+
|
13
|
+
configurations.each do |config_path|
|
14
|
+
config_path = File.expand_path config_path
|
15
|
+
if File.file? config_path
|
16
|
+
hash = YAML.load_file config_path
|
17
|
+
configatron.configure_from_hash hash
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require_relative 'config'
|
3
|
+
|
4
|
+
def set_dir_permissions(for_path:)
|
5
|
+
user = configatron.user
|
6
|
+
group = configatron.has_key?(:group) ? configatron.group : 'nogroup'
|
7
|
+
begin
|
8
|
+
FileUtils.chown_R user, group, for_path unless user.nil?
|
9
|
+
rescue ArgumentError
|
10
|
+
puts "Could not set permissions for '#{for_path}'"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_path(path)
|
15
|
+
begin
|
16
|
+
FileUtils.mkdir_p path
|
17
|
+
rescue Errno::EACCES
|
18
|
+
puts "Permission denied to create '#{path}'"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
config = configatron.to_h
|
23
|
+
config.each do |key, value|
|
24
|
+
if key.to_s.match /_directory/
|
25
|
+
path = File.expand_path value
|
26
|
+
create_path path
|
27
|
+
set_dir_permissions for_path: path if configatron.has_key? :user
|
28
|
+
end
|
29
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'moneta'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'config'
|
4
4
|
|
5
5
|
# A class to handle queueing through Moneta's key-value storage
|
6
6
|
class MonetaQueue
|
7
7
|
attr_reader :watched_queues
|
8
8
|
|
9
|
-
@@store = Moneta.new :File, dir: configatron.
|
9
|
+
@@store = Moneta.new :File, dir: File.expand_path(configatron.moneta_directory)
|
10
10
|
|
11
11
|
def initialize(name)
|
12
12
|
@name = name
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/sweatshop.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'sweatshop/moneta-queue'
|
2
|
+
require_relative 'sweatshop/queue-helper'
|
3
|
+
require_relative 'sweatshop/config'
|
4
|
+
|
5
|
+
require_relative 'sweatshop/payload/payload'
|
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
|
+
|
data/robot_sweatshop.eye
CHANGED
@@ -1,60 +1,60 @@
|
|
1
|
-
|
2
|
-
require_relative 'config'
|
1
|
+
require 'yaml'
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
CONFIG = YAML.load_file '/tmp/.robot_sweatshop-eye-config.yaml'
|
4
|
+
PID_PATH = CONFIG[:pidfile_directory]
|
5
|
+
LOG_PATH = CONFIG[:logfile_directory]
|
6
6
|
|
7
7
|
Eye.config do
|
8
|
-
logger
|
8
|
+
logger CONFIG[:log_file]
|
9
9
|
end
|
10
10
|
|
11
11
|
Eye.application :robot_sweatshop do
|
12
12
|
trigger :flapping, times: 10, within: 1.minute, retry_in: 10.minutes
|
13
13
|
check :cpu, every: 10.seconds, below: 100, times: 3
|
14
|
-
working_dir
|
15
|
-
uid "#{
|
16
|
-
gid "#{
|
14
|
+
working_dir CONFIG[:working_directory]
|
15
|
+
uid "#{CONFIG[:user]}" if CONFIG[:user]
|
16
|
+
gid "#{CONFIG[:group]}" if CONFIG[:group]
|
17
17
|
|
18
18
|
group 'input' do
|
19
19
|
process :http do
|
20
|
-
pid_file "#{
|
21
|
-
stdall "#{
|
22
|
-
start_command "
|
20
|
+
pid_file "#{PID_PATH}/input-http.pid"
|
21
|
+
stdall "#{LOG_PATH}/input-http.log"
|
22
|
+
start_command "#{__dir__}/bin/sweatshop-input-http"
|
23
23
|
daemonize true
|
24
24
|
end
|
25
25
|
end
|
26
26
|
group 'queue' do
|
27
27
|
process :handler do
|
28
|
-
pid_file "#{
|
29
|
-
stdall "#{
|
30
|
-
start_command "
|
28
|
+
pid_file "#{PID_PATH}/queue-handler.pid"
|
29
|
+
stdall "#{LOG_PATH}/queue-handler.log"
|
30
|
+
start_command "#{__dir__}/bin/sweatshop-queue-handler"
|
31
31
|
daemonize true
|
32
32
|
end
|
33
33
|
process :broadcaster do
|
34
|
-
pid_file "#{
|
35
|
-
stdall "#{
|
36
|
-
start_command "
|
34
|
+
pid_file "#{PID_PATH}/queue-broadcaster.pid"
|
35
|
+
stdall "#{LOG_PATH}/queue-broadcaster.log"
|
36
|
+
start_command "#{__dir__}/bin/sweatshop-queue-broadcaster #{configatron.eye.broadcaster_interval}"
|
37
37
|
daemonize true
|
38
38
|
end
|
39
39
|
end
|
40
40
|
group 'job' do
|
41
41
|
process :assembler do
|
42
|
-
pid_file "#{
|
43
|
-
stdall "#{
|
44
|
-
start_command "
|
42
|
+
pid_file "#{PID_PATH}/job-assembler.pid"
|
43
|
+
stdall "#{LOG_PATH}/job-assembler.log"
|
44
|
+
start_command "#{__dir__}/bin/sweatshop-job-assembler"
|
45
45
|
daemonize true
|
46
46
|
end
|
47
47
|
process :worker do
|
48
|
-
pid_file "#{
|
49
|
-
stdall "#{
|
50
|
-
start_command "
|
48
|
+
pid_file "#{PID_PATH}/job-worker.pid"
|
49
|
+
stdall "#{LOG_PATH}/job-worker.log"
|
50
|
+
start_command "#{__dir__}/bin/sweatshop-job-worker #{configatron.eye.worker_id}"
|
51
51
|
daemonize true
|
52
52
|
end
|
53
53
|
end
|
54
54
|
process :payload_parser do
|
55
|
-
pid_file "#{
|
56
|
-
stdall "#{
|
57
|
-
start_command "
|
55
|
+
pid_file "#{PID_PATH}/payload_parser.pid"
|
56
|
+
stdall "#{LOG_PATH}/payload_parser.log"
|
57
|
+
start_command "#{__dir__}/bin/sweatshop-payload-parser"
|
58
58
|
daemonize true
|
59
59
|
end
|
60
60
|
end
|
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.2.0'
|
4
4
|
gem.licenses = 'MIT'
|
5
5
|
gem.authors = ['Justin Scott']
|
6
6
|
gem.email = 'jvscott@gmail.com'
|
@@ -10,7 +10,8 @@ Gem::Specification.new do |gem|
|
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split("\n")
|
12
12
|
gem.test_files = `git ls-files -- kintama/**/*`.split("\n")
|
13
|
-
gem.executables = `git ls-files -- bin
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
14
|
+
gem.require_paths = ['lib']
|
14
15
|
|
15
16
|
gem.required_ruby_version = '>= 2.1'
|
16
17
|
|
@@ -26,4 +27,6 @@ Gem::Specification.new do |gem|
|
|
26
27
|
gem.add_development_dependency 'rake'
|
27
28
|
gem.add_development_dependency 'kintama'
|
28
29
|
gem.add_development_dependency 'http'
|
30
|
+
gem.add_development_dependency 'pry'
|
31
|
+
gem.add_development_dependency 'pry-byebug'
|
29
32
|
end
|
data/robot_sweatshop.testing.eye
CHANGED
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.2.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-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -164,10 +164,45 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: pry
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: pry-byebug
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
167
195
|
description: A lightweight, unopinionated CI server.
|
168
196
|
email: jvscott@gmail.com
|
169
197
|
executables:
|
170
198
|
- sweatshop
|
199
|
+
- sweatshop-input-http
|
200
|
+
- sweatshop-job-assembler
|
201
|
+
- sweatshop-job-worker
|
202
|
+
- sweatshop-payload-parser
|
203
|
+
- sweatshop-queue-broadcaster
|
204
|
+
- sweatshop-queue-handler
|
205
|
+
- sweatshop-queue-watcher
|
171
206
|
extensions: []
|
172
207
|
extra_rdoc_files: []
|
173
208
|
files:
|
@@ -177,18 +212,18 @@ files:
|
|
177
212
|
- LICENSE
|
178
213
|
- README.md
|
179
214
|
- Rakefile
|
180
|
-
- bin/lib/common.rb
|
181
|
-
- bin/lib/config.rb
|
182
|
-
- bin/lib/inspect.rb
|
183
|
-
- bin/lib/job.rb
|
184
|
-
- bin/lib/setup.rb
|
185
|
-
- bin/lib/start.rb
|
186
215
|
- bin/sweatshop
|
187
|
-
-
|
188
|
-
-
|
189
|
-
-
|
216
|
+
- bin/sweatshop-input-http
|
217
|
+
- bin/sweatshop-job-assembler
|
218
|
+
- bin/sweatshop-job-worker
|
219
|
+
- bin/sweatshop-payload-parser
|
220
|
+
- bin/sweatshop-queue-broadcaster
|
221
|
+
- bin/sweatshop-queue-handler
|
222
|
+
- bin/sweatshop-queue-watcher
|
223
|
+
- config.defaults.yaml
|
190
224
|
- kintama/README.md
|
191
225
|
- kintama/data/payload_data.yaml
|
226
|
+
- kintama/data/test_job.yaml
|
192
227
|
- kintama/end-to-end_spec.rb
|
193
228
|
- kintama/input_http_spec.rb
|
194
229
|
- kintama/job_assembler_spec.rb
|
@@ -201,18 +236,18 @@ files:
|
|
201
236
|
- kintama/shared/helpers.rb
|
202
237
|
- kintama/shared/process_spawning.rb
|
203
238
|
- lib/README.md
|
204
|
-
- lib/
|
205
|
-
- lib/
|
206
|
-
- lib/
|
207
|
-
- lib/
|
208
|
-
- lib/
|
209
|
-
- lib/
|
210
|
-
- lib/
|
211
|
-
- lib/queue
|
212
|
-
- lib/
|
213
|
-
- lib/
|
214
|
-
- lib/
|
215
|
-
- lib/queue
|
239
|
+
- lib/sweatshop.rb
|
240
|
+
- lib/sweatshop/cli/common.rb
|
241
|
+
- lib/sweatshop/cli/config.rb
|
242
|
+
- lib/sweatshop/cli/job.rb
|
243
|
+
- lib/sweatshop/cli/start.rb
|
244
|
+
- lib/sweatshop/config.rb
|
245
|
+
- lib/sweatshop/create-config-directories.rb
|
246
|
+
- lib/sweatshop/moneta-queue.rb
|
247
|
+
- lib/sweatshop/payload/bitbucket.rb
|
248
|
+
- lib/sweatshop/payload/github.rb
|
249
|
+
- lib/sweatshop/payload/payload.rb
|
250
|
+
- lib/sweatshop/queue-helper.rb
|
216
251
|
- robot_sweatshop.eye
|
217
252
|
- robot_sweatshop.gemspec
|
218
253
|
- robot_sweatshop.production.eye
|
@@ -243,5 +278,6 @@ specification_version: 4
|
|
243
278
|
summary: Robot Sweatshop
|
244
279
|
test_files:
|
245
280
|
- kintama/data/payload_data.yaml
|
281
|
+
- kintama/data/test_job.yaml
|
246
282
|
- kintama/shared/helpers.rb
|
247
283
|
- kintama/shared/process_spawning.rb
|
data/bin/lib/config.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
require 'fileutils'
|
3
|
-
require_relative '../../config'
|
4
|
-
|
5
|
-
def default_config
|
6
|
-
File.read "#{__dir__}/../../config.yaml"
|
7
|
-
end
|
8
|
-
|
9
|
-
def user_config_file
|
10
|
-
'/etc/robot_sweatshop/config.yaml'
|
11
|
-
end
|
12
|
-
|
13
|
-
def remove_user_config
|
14
|
-
FileUtils.rm_rf user_config_file
|
15
|
-
notify :success, 'Removing current user config file'
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_and_edit_user_config
|
19
|
-
create_and_edit user_config_file, with_default: default_config
|
20
|
-
end
|
data/bin/lib/inspect.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
def valid_lists?(job)
|
2
|
-
errors = false
|
3
|
-
%w(branch_whitelist commands).each do |list|
|
4
|
-
if job[list].nil? || job[list].empty?
|
5
|
-
notify :failure, "#{list} empty or not found"
|
6
|
-
errors = true
|
7
|
-
end
|
8
|
-
end
|
9
|
-
errors
|
10
|
-
end
|
11
|
-
|
12
|
-
def valid_environment?(job)
|
13
|
-
errors = false
|
14
|
-
job['environment'].each do |key, value|
|
15
|
-
unless value.is_a? String
|
16
|
-
notify :warning, "Non-string value for '#{key}'"
|
17
|
-
errors = true
|
18
|
-
end
|
19
|
-
end
|
20
|
-
errors
|
21
|
-
end
|
22
|
-
|
23
|
-
def valid_yaml?(job)
|
24
|
-
if job
|
25
|
-
true
|
26
|
-
else
|
27
|
-
notify :failure, "Invalid YAML"
|
28
|
-
false
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def validate(job_file)
|
33
|
-
unless File.file?(job_file)
|
34
|
-
notify :failure, 'Job not found. Create it with \'workshop job\''
|
35
|
-
else
|
36
|
-
job = YAML.load_file job_file
|
37
|
-
return unless valid_yaml?(job)
|
38
|
-
errors = valid_lists?(job) |
|
39
|
-
valid_environment?(job)
|
40
|
-
notify :success, 'Valid job configuration' unless errors
|
41
|
-
end
|
42
|
-
end
|
data/bin/lib/job.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require_relative 'common'
|
2
|
-
|
3
|
-
def empty_job
|
4
|
-
"---\nbranch_whitelist:\n- master\n\ncommands:\n- echo 'Hello $WORLD!'\n\nenvironment:\n WORLD: Earth\n"
|
5
|
-
end
|
6
|
-
|
7
|
-
def create_and_edit_job(job_path)
|
8
|
-
create_and_edit job_path, with_default: empty_job
|
9
|
-
end
|
10
|
-
|
11
|
-
def list_jobs
|
12
|
-
puts Dir.glob("#{__dir__}/../../jobs/*").map { |file| File.basename(file, '.yaml') }
|
13
|
-
end
|
data/bin/lib/setup.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'configatron'
|
3
|
-
require_relative 'common'
|
4
|
-
require_relative '../../config'
|
5
|
-
|
6
|
-
config_directories = [
|
7
|
-
configatron.common.logfile_directory,
|
8
|
-
configatron.common.pidfile_directory,
|
9
|
-
configatron.common.user_config_directory,
|
10
|
-
configatron.queue.moneta_directory,
|
11
|
-
configatron.assembler.job_directory,
|
12
|
-
configatron.worker.workspace_directory
|
13
|
-
]
|
14
|
-
config_directories.each do |directory|
|
15
|
-
user = configatron.common.user
|
16
|
-
group = configatron.common.group
|
17
|
-
if Dir.exists? directory
|
18
|
-
notify :info, "'#{directory}' already exists"
|
19
|
-
else
|
20
|
-
FileUtils.mkdir_p directory
|
21
|
-
notify :success, "Created '#{directory}' and set owner as #{user}:#{group}"
|
22
|
-
end
|
23
|
-
FileUtils.chown_R user, group, directory
|
24
|
-
notify :success, "Recursively set owner of '#{directory}' as #{user}:#{group}\n\n"
|
25
|
-
end
|
data/bin/lib/start.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
def start_sweatshop(for_environment:)
|
2
|
-
eye_config = "#{__dir__}/../../robot_sweatshop.#{for_environment}.eye"
|
3
|
-
output = `eye load #{eye_config}`
|
4
|
-
if $?.exitstatus != 0
|
5
|
-
notify :failure, output
|
6
|
-
else
|
7
|
-
notify :success, "Robot Sweatshop loaded with a #{for_environment} configuration"
|
8
|
-
notify :info, `eye restart robot_sweatshop`
|
9
|
-
puts 'Check \'eye --help\' for more info on debugging'
|
10
|
-
end
|
11
|
-
end
|
data/config.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'configatron'
|
2
|
-
require 'yaml'
|
3
|
-
|
4
|
-
# TODO: namespace to avoid collisions?
|
5
|
-
|
6
|
-
configurations = [
|
7
|
-
"#{__dir__}/config.yaml",
|
8
|
-
"#{__dir__}/config.user.yaml",
|
9
|
-
"/etc/robot_sweatshop/config.yaml"
|
10
|
-
]
|
11
|
-
configurations.each do |config_path|
|
12
|
-
if File.file? config_path
|
13
|
-
hash = YAML.load_file config_path
|
14
|
-
configatron.configure_from_hash hash
|
15
|
-
end
|
16
|
-
end
|
data/config.yaml
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
common:
|
2
|
-
pidfile_directory: /var/run/robot_sweatshop
|
3
|
-
logfile_directory: /var/log/robot_sweatshop
|
4
|
-
user_config_directory: /etc/robot_sweatshop
|
5
|
-
user: jscott
|
6
|
-
group: nogroup
|
7
|
-
|
8
|
-
input:
|
9
|
-
http:
|
10
|
-
port: 8080
|
11
|
-
bind: 0.0.0.0
|
12
|
-
|
13
|
-
queue:
|
14
|
-
moneta_directory: /var/db/robot_sweatshop
|
15
|
-
|
16
|
-
assembler:
|
17
|
-
job_directory: /etc/robot_sweatshop/jobs
|
18
|
-
|
19
|
-
worker:
|
20
|
-
workspace_directory: /etc/robot_sweatshop/workspaces
|