robot_sweatshop 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![Improved architecture diagram](http://40.media.tumblr.com/8a5b6ca59c0d93c4ce6fc6b733932a5f/tumblr_nko478zp9N1qh941oo1_1280.jpg)
|
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
|