rudder 0.1.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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +16 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +53 -0
  8. data/LICENSE +21 -0
  9. data/README.md +101 -0
  10. data/Rakefile +24 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/docker-compose.yml +26 -0
  14. data/docs/Rudder.html +382 -0
  15. data/docs/Rudder/DSL.html +456 -0
  16. data/docs/Rudder/DSL/Component.html +645 -0
  17. data/docs/Rudder/DSL/Group.html +733 -0
  18. data/docs/Rudder/DSL/Job.html +487 -0
  19. data/docs/Rudder/DSL/Pipeline.html +1869 -0
  20. data/docs/Rudder/DSL/Resource.html +584 -0
  21. data/docs/Rudder/DSL/ResourceType.html +223 -0
  22. data/docs/Rudder/DSL/Util.html +324 -0
  23. data/docs/_index.html +211 -0
  24. data/docs/class_list.html +51 -0
  25. data/docs/css/common.css +1 -0
  26. data/docs/css/full_list.css +58 -0
  27. data/docs/css/style.css +496 -0
  28. data/docs/file.README.html +191 -0
  29. data/docs/file_list.html +56 -0
  30. data/docs/frames.html +17 -0
  31. data/docs/index.html +191 -0
  32. data/docs/js/app.js +303 -0
  33. data/docs/js/full_list.js +216 -0
  34. data/docs/js/jquery.js +4 -0
  35. data/docs/method_list.html +347 -0
  36. data/docs/top-level-namespace.html +110 -0
  37. data/examples/README.md +6 -0
  38. data/examples/groups/README.md +12 -0
  39. data/examples/groups/groups_pipeline.rb +34 -0
  40. data/examples/groups/jobs/bash_stuff/date.rb +16 -0
  41. data/examples/groups/jobs/bash_stuff/hello.rb +17 -0
  42. data/examples/groups/jobs/git_stuff/log.rb +22 -0
  43. data/examples/groups/jobs/git_stuff/ls.rb +21 -0
  44. data/examples/groups/resources/rudder_git.rb +6 -0
  45. data/examples/groups/resources/timer.rb +5 -0
  46. data/examples/hello_world_pipeline.rb +44 -0
  47. data/examples/images/groups/groups_all.png +0 -0
  48. data/examples/images/groups/groups_bash_stuff.png +0 -0
  49. data/examples/images/groups/groups_git_stuff.png +0 -0
  50. data/examples/images/hello_world.png +0 -0
  51. data/examples/images/includes/includes.png +0 -0
  52. data/examples/images/shared/borrows.png +0 -0
  53. data/examples/images/shared/common.png +0 -0
  54. data/examples/images/shared/wrapper.png +0 -0
  55. data/examples/includes/README.md +7 -0
  56. data/examples/includes/includes_pipeline.rb +6 -0
  57. data/examples/includes/jobs/log.rb +15 -0
  58. data/examples/includes/resources/rudder_git.rb +5 -0
  59. data/examples/shared/README.md +21 -0
  60. data/examples/shared/borrows_pipeline.rb +31 -0
  61. data/examples/shared/common_pipeline.rb +34 -0
  62. data/examples/shared/wrapper_pipeline.rb +51 -0
  63. data/exe/rudder +52 -0
  64. data/lib/rudder.rb +35 -0
  65. data/lib/rudder/dsl.rb +54 -0
  66. data/lib/rudder/dsl/component.rb +79 -0
  67. data/lib/rudder/dsl/group.rb +110 -0
  68. data/lib/rudder/dsl/job.rb +65 -0
  69. data/lib/rudder/dsl/pipeline.rb +374 -0
  70. data/lib/rudder/dsl/resource.rb +82 -0
  71. data/lib/rudder/dsl/resource_type.rb +45 -0
  72. data/lib/rudder/dsl/util.rb +48 -0
  73. data/lib/rudder/version.rb +5 -0
  74. data/lib/tasks/docker.rb +11 -0
  75. data/rudder.gemspec +29 -0
  76. metadata +189 -0
@@ -0,0 +1,6 @@
1
+ # Examples
2
+
3
+ These examples show several examples of how to use `rudder`. Start
4
+ in [`hello_world_pipeline.rb`](hello_world_pipeline.rb):
5
+
6
+ ![Hello World Pipeline](images/hello_world.png)
@@ -0,0 +1,12 @@
1
+ # Groups Example
2
+
3
+ The [`groups_pipeline.rb`](./groups_pipeline.rb) shows how concourse groups can be utilized
4
+ within `rudder`. This pipeline also shows how to indiscriminately import
5
+ pipelines from other directories.
6
+
7
+ - The All group:
8
+ ![Groups Pipeline](../images/groups/groups_all.png)
9
+ - The Bash Stuff group:
10
+ ![Groups Pipeline](../images/groups/groups_bash_stuff.png)
11
+ - The Git Stuff group:
12
+ ![Groups Pipeline](../images/groups/groups_git_stuff.png)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ @parent_dir = File.dirname(__FILE__)
4
+ def relative_files(path)
5
+ Dir[File.join(@parent_dir, path)]
6
+ end
7
+
8
+ # Load all the resources
9
+ relative_files('resources/*').each do |path|
10
+ # Pipline#load includes always loads files relative to where itself, so
11
+ # we need to remove the parent directory from this path
12
+ res = load path.sub(@parent_dir, '')
13
+ resources.merge! res.resources
14
+ end
15
+
16
+ # Load all the jobs and stick them in groups by directory
17
+ relative_files('jobs/*').each do |group_dir|
18
+ group_name = File.basename group_dir
19
+ group group_name do |pipeline|
20
+ Dir[File.join(group_dir, '*')].each do |job_path|
21
+ parent_dir = File.dirname __FILE__
22
+ job_pipe = pipeline.load(job_path.sub(parent_dir, ''), resources: pipeline.resources)
23
+ pipeline.jobs.merge! job_pipe.jobs
24
+ job_pipe.jobs.keys.each { |job_name| job job_name }
25
+ end
26
+ end
27
+ end
28
+
29
+ # Add all of the jobs to a super group
30
+ group :all do |pipeline|
31
+ pipeline.jobs.keys.each do |job_name|
32
+ jobs << job_name
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ time_resources = @resources.values.select { |r| r.type == :time }
4
+
5
+ time_resources.each do |r|
6
+ job :date do
7
+ plan << { get: r.name, trigger: true }
8
+ plan << { task: 'print_date', config: {
9
+ platform: 'linux',
10
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
11
+ run: {
12
+ path: 'date'
13
+ }
14
+ } }
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ time_resources = resources.values.select { |r| r.type == :time }
4
+
5
+ time_resources.each do |r|
6
+ job :hello do
7
+ plan << { get: r.name, trigger: true }
8
+ plan << { task: 'print_hello', config: {
9
+ platform: 'linux',
10
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
11
+ run: {
12
+ path: 'echo',
13
+ args: ['Hello']
14
+ }
15
+ } }
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ git_resources = resources.values.select { |r| r.type == :git }
4
+
5
+ git_resources.each do |r|
6
+ job "git log #{r.name}" do
7
+ plan << { get: r.name, trigger: true }
8
+ task = {
9
+ task: "git log #{r.name}", config: {
10
+ inputs: [name: r.name],
11
+ platform: 'linux',
12
+ image_resource: { type: 'docker-image', source: { repository: 'alpine/git' } },
13
+ run: {
14
+ path: 'git',
15
+ args: ['--git-dir', File.join(r.name.to_s, '.git'),
16
+ '--no-pager', 'log']
17
+ }
18
+ }
19
+ }
20
+ plan << task
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ git_resources = resources.values.select { |r| r.type == :git }
4
+
5
+ git_resources.each do |r|
6
+ job "ls #{r.name}" do
7
+ plan << { get: r.name, trigger: true }
8
+ task = {
9
+ task: "ls #{r.name}", config: {
10
+ inputs: [name: r.name],
11
+ platform: 'linux',
12
+ image_resource: { type: 'docker-image', source: { repository: 'alpine/git' } },
13
+ run: {
14
+ path: 'ls',
15
+ args: [r.name]
16
+ }
17
+ }
18
+ }
19
+ plan << task
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ resource :rudder_git, :git do
4
+ source[:uri] = 'https://github.com/jhmcstanton/rudder.git'
5
+ source[:branch] = 'master'
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ resource :timer, :time do
4
+ source[:interval] = '5m'
5
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ resource :rudder_git, :git do
4
+ # The source field dictionary is available to be directly interacted with
5
+ source[:uri] = 'https://github.com/jhmcstanton/rudder.git'
6
+ source[:branch] = 'master'
7
+ end
8
+
9
+ resource :timer, :time do
10
+ # The source field can also be assigned via a method
11
+ source(interval: '5m')
12
+ end
13
+
14
+ job :getter do
15
+ plan [in_parallel: [{ get: :rudder_git }, { get: :timer, trigger: true }]]
16
+ end
17
+
18
+ job :hello_world do
19
+ # Plan array can be hooked into directly
20
+ plan << { get: :timer, trigger: true, passed: [:getter] }
21
+ plan << { task: 'print_hello', config: {
22
+ platform: 'linux',
23
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
24
+ run: {
25
+ path: 'echo',
26
+ args: ['Hello', 'World!']
27
+ }
28
+ } }
29
+ end
30
+
31
+ # pipeline here allows access to previously defined pipeline components
32
+ job :cat_self do |pipeline|
33
+ # The plan can also be appended to as a method
34
+ plan({ get: :rudder_git, trigger: true, passed: [:getter] },
35
+ task: 'cat this pipeline', config: {
36
+ inputs: [name: :rudder_git],
37
+ platform: 'linux',
38
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
39
+ run: {
40
+ path: 'cat',
41
+ args: [pipeline.rudder_git.sub_path('examples/hello_world.rb')]
42
+ }
43
+ })
44
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,7 @@
1
+ # Includes Example
2
+
3
+ The [`includes_pipeline.rb`](./includes_pipeline.rb) pipeline shows how to load pipeline components
4
+ (jobs, resources, resource_types, groups) from files and include them
5
+ into your pipelines.
6
+
7
+ ![Includes Pipeline](../images/includes/includes.png)
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ load_component 'resources/rudder_git.rb', :resource, :rudder_git
4
+
5
+ job = load_component 'jobs/log.rb', :job, :log_rudder_git
6
+ job.plan.insert(0, get: :rudder_git, trigger: true)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ task = {
4
+ task: 'git log', config: {
5
+ # input still needed
6
+ platform: 'linux',
7
+ image_resource: { type: 'docker-image', source: { repository: 'alpine/git' } },
8
+ run: {
9
+ path: 'find',
10
+ args: ['.', '-iname', '*.git', '-exec',
11
+ 'git', '--git-dir', '{}', '--no-pager', 'log', ';']
12
+ }
13
+ }
14
+ }
15
+ plan << task
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ type :git
4
+ source[:uri] = 'https://github.com/jhmcstanton/rudder.git'
5
+ source[:branch] = 'master'
@@ -0,0 +1,21 @@
1
+ # Shared Example
2
+
3
+ This example is a bit contrived, but serves to illustrate how joining pipelines works.
4
+
5
+ [`common_pipeline.rb`](./common_pipeline.rb) is a full, standalone pipeline with resources
6
+ and several jobs that is fully flyable.
7
+
8
+ ![Common Pipeline](../images/shared/common.png)
9
+
10
+ [`wrapper_pipeline.rb`](./wrapper_pipeline.rb) is another full pipeline that incorporates
11
+ the entirety of `common_pipeline.rb` and augments it with an additional timer, one new
12
+ job that requires the final job from `common_pipeline.rb`, and its own job that only
13
+ depends on a single resource from the common pipeline.
14
+
15
+ ![Wrapper Pipeline](../images/shared/wrapper.png)
16
+
17
+ [`borrows_pipeline.rb`](./borrows_pipeline.rb) is a single job pipeline that borrows
18
+ the git resource from the `common_pipeline.rb` (actually, it would borrow any git
19
+ resource from that pipeline, there just happens to be only one right now).
20
+
21
+ ![Borrows Pipeline](../images/shared/borrows.png)
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ common = load 'common_pipeline.rb'
4
+
5
+ resource :timer, :time do
6
+ source[:interval] = '30m'
7
+ end
8
+
9
+ # Borrow any git resources defined in common
10
+ git_resources = common.resources.select { |_name, r| r.type == :git }
11
+ resources.merge! git_resources
12
+
13
+ job 'Just borrowing the git resource' do
14
+ git_names = git_resources.keys
15
+ gets = git_names.map { |name| { get: name } }
16
+ gets << { get: :timer, trigger: true }
17
+ plan [in_parallel: gets]
18
+
19
+ task = {
20
+ task: 'ls all the gits', config: {
21
+ platform: 'linux',
22
+ inputs: [name: :rudder_git],
23
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
24
+ run: {
25
+ path: 'ls',
26
+ args: git_names
27
+ }
28
+ }
29
+ }
30
+ plan << task
31
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ resource :rudder_git, :git do
4
+ source[:uri] = 'https://github.com/jhmcstanton/rudder.git'
5
+ source[:branch] = 'master'
6
+ end
7
+
8
+ get_rudder = { get: :rudder_git, trigger: true }
9
+
10
+ print_hello = {
11
+ task: 'print_hello', config: {
12
+ platform: 'linux',
13
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
14
+ run: {
15
+ path: 'echo',
16
+ args: ['Hello', 'World!']
17
+ }
18
+ }
19
+ }
20
+
21
+ def mk_name(job_index)
22
+ "Yo #{job_index}"
23
+ end
24
+
25
+ num_jobs = 3
26
+ (1..num_jobs).each do |i|
27
+ name = mk_name i
28
+ job name do |p|
29
+ get = get_rudder.dup
30
+ get[:passed] = [p.mk_name(i - 1)] if i > 1
31
+ plan << get
32
+ plan << print_hello
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ common = load('common_pipeline.rb')
4
+
5
+ resource :timer, :time do
6
+ source[:interval] = '5m'
7
+ end
8
+
9
+ # Add a timer to the first job
10
+ get_timer_task = { get: :timer, trigger: true }
11
+ start_plan = common.jobs.values.first.plan
12
+ start_plan << get_timer_task
13
+
14
+ resources.merge! common.resources
15
+ jobs .merge! common.jobs
16
+
17
+ job 'An extra job that the wrapper pipeline requires' do
18
+ plan << get_timer_task
19
+ date = {
20
+ task: 'print the date', config: {
21
+ platform: 'linux',
22
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
23
+ run: {
24
+ path: 'date'
25
+ }
26
+ }
27
+ }
28
+ plan << date
29
+ end
30
+
31
+ job 'Goodbye from the Wrapper Pipeline' do |_pipeline|
32
+ # Get the last job defined in the previous pipeline
33
+ # so that we can depend on it in this job
34
+ last_job = common.jobs.values.last
35
+ last_job.plan.select { |task| task.key? :get }.each do |task|
36
+ task = task.dup
37
+ task[:passed] = [last_job.name]
38
+ plan << task
39
+ end
40
+ task = {
41
+ task: 'print_outer', config: {
42
+ platform: 'linux',
43
+ image_resource: { type: 'docker-image', source: { repository: 'busybox' } },
44
+ run: {
45
+ path: 'echo',
46
+ args: ['This is the outer pipeline. Good bye!']
47
+ }
48
+ }
49
+ }
50
+ plan << task
51
+ end
data/exe/rudder ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'optparse'
5
+ require 'yaml'
6
+
7
+ require 'rudder'
8
+
9
+ name = File.basename __FILE__
10
+
11
+ # TODO: Figure out a nice way to join these options with fly's without
12
+ # tieing them together
13
+ options = {}
14
+ optparse = OptionParser.new do |opts|
15
+ opts.banner = "Usage: #{name} [options]"
16
+
17
+ opts.on('-o', '--output YAML_PATH', 'YAML_PATH to write the pipeline config') do |p|
18
+ options[:output] = p
19
+ end
20
+
21
+ opts.on('-c', '--config RUDDER_CONFIG', 'Path to the RUDDER_CONFIG file to evaluate') do |c|
22
+ options[:rudder] = c
23
+ end
24
+
25
+ opts.on('-v', '--version', 'Show version') do
26
+ options[:version] = true
27
+ end
28
+ end
29
+ optparse.parse!
30
+
31
+ if options[:version]
32
+ puts "Rudder Version: #{Rudder::VERSION}"
33
+ exit
34
+ end
35
+
36
+ unless options[:rudder]
37
+ puts 'Must provide RUDDER_CONFIG as option'
38
+ puts optparse.help
39
+ exit 1
40
+ end
41
+
42
+ pipeline = Rudder.compile(options[:rudder])
43
+
44
+ output = STDOUT
45
+ if options[:output]
46
+ output = File.open(options[:output], 'w+')
47
+ at_exit do
48
+ output.close
49
+ end
50
+ end
51
+
52
+ Rudder.dump(pipeline, output)