greenhouse 0.0.3

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/bin/greenhouse +9 -0
  3. data/lib/greenhouse/cli.rb +88 -0
  4. data/lib/greenhouse/commands/add.rb +32 -0
  5. data/lib/greenhouse/commands/command.rb +88 -0
  6. data/lib/greenhouse/commands/configure.rb +9 -0
  7. data/lib/greenhouse/commands/help.rb +45 -0
  8. data/lib/greenhouse/commands/init.rb +93 -0
  9. data/lib/greenhouse/commands/launch.rb +113 -0
  10. data/lib/greenhouse/commands/new.rb +42 -0
  11. data/lib/greenhouse/commands/pull.rb +45 -0
  12. data/lib/greenhouse/commands/purge.rb +91 -0
  13. data/lib/greenhouse/commands/push.rb +45 -0
  14. data/lib/greenhouse/commands/remove.rb +32 -0
  15. data/lib/greenhouse/commands/start.rb +21 -0
  16. data/lib/greenhouse/commands/status.rb +50 -0
  17. data/lib/greenhouse/commands/sync.rb +42 -0
  18. data/lib/greenhouse/commands.rb +32 -0
  19. data/lib/greenhouse/projects/application.rb +19 -0
  20. data/lib/greenhouse/projects/collection.rb +23 -0
  21. data/lib/greenhouse/projects/engine.rb +6 -0
  22. data/lib/greenhouse/projects/gem.rb +6 -0
  23. data/lib/greenhouse/projects/project.rb +77 -0
  24. data/lib/greenhouse/projects/repository.rb +197 -0
  25. data/lib/greenhouse/projects.rb +86 -0
  26. data/lib/greenhouse/resources/dotenv_file.rb +69 -0
  27. data/lib/greenhouse/resources/file_resource.rb +50 -0
  28. data/lib/greenhouse/resources/ignore_file.rb +115 -0
  29. data/lib/greenhouse/resources/procfile.rb +144 -0
  30. data/lib/greenhouse/resources/projects_file.rb +44 -0
  31. data/lib/greenhouse/resources.rb +10 -0
  32. data/lib/greenhouse/scripts/argument.rb +36 -0
  33. data/lib/greenhouse/scripts/arguments.rb +28 -0
  34. data/lib/greenhouse/scripts/invalid_argument.rb +6 -0
  35. data/lib/greenhouse/scripts/script.rb +109 -0
  36. data/lib/greenhouse/scripts.rb +4 -0
  37. data/lib/greenhouse/tasks/add_project.rb +57 -0
  38. data/lib/greenhouse/tasks/generate_procfile.rb +22 -0
  39. data/lib/greenhouse/tasks/project_status.rb +37 -0
  40. data/lib/greenhouse/tasks/project_task.rb +363 -0
  41. data/lib/greenhouse/tasks/pull_project.rb +14 -0
  42. data/lib/greenhouse/tasks/purge_project.rb +13 -0
  43. data/lib/greenhouse/tasks/push_project.rb +14 -0
  44. data/lib/greenhouse/tasks/remove_greenhouse_files.rb +58 -0
  45. data/lib/greenhouse/tasks/remove_project.rb +15 -0
  46. data/lib/greenhouse/tasks/sync_project.rb +19 -0
  47. data/lib/greenhouse/tasks/task.rb +25 -0
  48. data/lib/greenhouse/tasks.rb +20 -0
  49. data/lib/greenhouse/version.rb +20 -0
  50. data/lib/greenhouse.rb +12 -0
  51. metadata +165 -0
@@ -0,0 +1,69 @@
1
+ module Greenhouse
2
+ module Resources
3
+ class DotenvFile
4
+ include FileResource
5
+
6
+ attr_reader :config
7
+
8
+ class ConfigVars < Hash
9
+ def format_key(key)
10
+ key.to_s.gsub(/[^a-z\d_]+/i, "_").upcase
11
+ end
12
+
13
+ def [](key)
14
+ super(format_key(key))
15
+ end
16
+
17
+ def []=(key, value)
18
+ super(format_key(key), value)
19
+ end
20
+
21
+ def initialize(hash={})
22
+ hash.each { |k,v| self[k] = v }
23
+ end
24
+ end
25
+
26
+ def config=(hash)
27
+ @config = ConfigVars.new(hash)
28
+ end
29
+
30
+ def reload
31
+ @config = ConfigVars.new
32
+ return @config unless exists?
33
+ # pulled this straight from Dotenv, too bad there's no simple Dotenv.parse method in the gem
34
+ read do |line|
35
+ if line =~ /\A(?:export\s+)?([\w\.]+)(?:=|: ?)(.*)\z/
36
+ key = $1
37
+ case val = $2
38
+ # Remove single quotes
39
+ when /\A'(.*)'\z/ then @config[key] = $1
40
+ # Remove double quotes and unescape string preserving newline characters
41
+ when /\A"(.*)"\z/ then @config[key] = $1.gsub('\n', "\n").gsub(/\\(.)/, '\1')
42
+ else @config[key] = val
43
+ end
44
+ end
45
+ end
46
+ @config
47
+ end
48
+
49
+ def write
50
+ open("w") do |f|
51
+ @config.each do |key,val|
52
+ f.write("#{key}=#{val}\n")
53
+ end
54
+ end
55
+ end
56
+
57
+ def unlink
58
+ super
59
+ reload
60
+ end
61
+
62
+ def initialize(path)
63
+ super
64
+ reload
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,50 @@
1
+ module Greenhouse
2
+ module Resources
3
+ module FileResource
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ end
10
+
11
+ module InstanceMethods
12
+ def self.included(base)
13
+ base.send :attr_reader, :path
14
+ end
15
+
16
+ def exists?
17
+ File.exists?(path)
18
+ end
19
+
20
+ def open(mode, &block)
21
+ File.open(path, mode, &block)
22
+ end
23
+
24
+ def lines(reload=false)
25
+ @lines = nil if reload
26
+ @lines ||= [] unless exists?
27
+ @lines ||= File.read(path).split("\n")
28
+ @lines
29
+ end
30
+
31
+ def read(&block)
32
+ lines(true).each_with_index(&block)
33
+ end
34
+
35
+ def unlink
36
+ File.unlink(path) if exists?
37
+ end
38
+
39
+ def chdir(&block)
40
+ Dir.chdir(File.expand_path("../", path), &block)
41
+ end
42
+
43
+ def initialize(path)
44
+ @path = File.expand_path(path)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,115 @@
1
+ module Greenhouse
2
+ module Resources
3
+ class IgnoreFile
4
+ include FileResource
5
+
6
+ class IgnoredFiles < Array
7
+
8
+ def unshift(file)
9
+ if !file.is_a?(IgnoredFile)
10
+ file = IgnoredFile.new(file, @ignore_file.lines.length)
11
+ end
12
+ super(file)
13
+ @ignore_file.lines[file.line] = file.to_s
14
+ end
15
+
16
+ def push(file)
17
+ if !file.is_a?(IgnoredFile)
18
+ file = IgnoredFile.new(file, @ignore_file.lines.length)
19
+ end
20
+ super(file)
21
+ @ignore_file.lines[file.line] = file.to_s
22
+ end
23
+
24
+ def <<(file)
25
+ push(file)
26
+ end
27
+
28
+ def []=(index,file)
29
+ delete_at index if index < length
30
+ file = IgnoredFile.new(file, @ignore_file.lines.length) if !file.is_a?(IgnoredFile)
31
+ super(index,file)
32
+ @ignore_file.lines[file.line] = file.to_s
33
+ end
34
+
35
+ def delete(filename)
36
+ # TODO delete any comments immediately preceding the filename
37
+ deleted = super(select { |f| f.file == filename}.first)
38
+ @ignore_file.ignored.each do |ignored|
39
+ next if ignored.line < deleted.line
40
+ ignored.line -= 1
41
+ end
42
+ line = @ignore_file.lines.slice!(deleted.line,1)
43
+ deleted
44
+ end
45
+
46
+ def delete_at(index)
47
+ delete self[index].file
48
+ end
49
+
50
+ def delete_if(&block)
51
+ select(&block).map { |ignored| delete ignored.file }
52
+ end
53
+
54
+ def keep_if(&block)
55
+ kept = select(&block)
56
+ clone.select { |ignored| !kept.map(&:file).include?(ignored.file) }.map { |ignored| delete ignored.file }
57
+ end
58
+
59
+ def initialize(ignore_file)
60
+ @ignore_file = ignore_file
61
+ super()
62
+ end
63
+ end
64
+
65
+ class IgnoredFile
66
+ attr_accessor :file, :line
67
+
68
+ def to_s
69
+ @file.to_s
70
+ end
71
+
72
+ def inspect
73
+ to_s
74
+ end
75
+
76
+ def initialize(file, line)
77
+ @file = file
78
+ @line = line
79
+ end
80
+ end
81
+
82
+ attr_accessor :ignored
83
+
84
+ def write
85
+ ignored.each { |ignored| lines[ignored.line] = ignored.to_s}
86
+ open('w') do |ifile|
87
+ lines.each do |line|
88
+ ifile.write "#{line}\n"
89
+ end
90
+ end
91
+ end
92
+ alias_method :save, :write
93
+
94
+ def reload
95
+ @ignored = IgnoredFiles.new(self)
96
+ return @ignored unless exists?
97
+ read do |line,l|
98
+ next if line.strip[0] == "#" || line.strip.empty?
99
+ @ignored << IgnoredFile.new(line,l)
100
+ end
101
+ @ignored
102
+ end
103
+
104
+ def unlink
105
+ super
106
+ reload
107
+ end
108
+
109
+ def initialize(path)
110
+ super
111
+ reload
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,144 @@
1
+ module Greenhouse
2
+ module Resources
3
+ class Procfile
4
+ include FileResource
5
+
6
+ class Processes < Hash
7
+ def [](key)
8
+ super(key.to_s)
9
+ end
10
+
11
+ def []=(key, value)
12
+ if value.is_a?(Process)
13
+ super(key.to_s, value)
14
+ else
15
+ parr = value.strip.split(":")
16
+ key = parr.slice!(0)
17
+ command = parr.join(":").strip
18
+ # TODO might need to rework this line index, won't account for blank/comment lines at the end of the file
19
+ value = Process.new(key, command, (values.map(&:line).sort.last || -1) + 1)
20
+ super(key.to_s, value)
21
+ end
22
+ @procfile.lines[value.line] = value.to_s
23
+ end
24
+
25
+ def delete(key)
26
+ del = super(key)
27
+ @procfile.processes.each do |key,process|
28
+ next if process.line < del.line
29
+ process.line -= 1
30
+ end
31
+ line = @procfile.lines.slice!(del.line,1)
32
+ del
33
+ end
34
+
35
+ def delete_if(&block)
36
+ select(&block).keys.map { |key| delete key }
37
+ end
38
+
39
+ def keep_if(&block)
40
+ kept = select(&block)
41
+ clone.select { |key,process| !kept.keys.include?(key) }.keys.map { |key| delete key }
42
+ end
43
+
44
+ def initialize(procfile)
45
+ @procfile = procfile
46
+ end
47
+ end
48
+
49
+ class Process
50
+ attr_accessor :key, :command, :line
51
+
52
+ def enabled?
53
+ !@disabled
54
+ end
55
+
56
+ def disabled?
57
+ @disabled
58
+ end
59
+
60
+ def enable
61
+ @disabled = false
62
+ end
63
+
64
+ def disable
65
+ @disabled = true
66
+ end
67
+
68
+ def to_s
69
+ "#{"#" if disabled?}#{key}: #{command}"
70
+ end
71
+
72
+ def inspect
73
+ to_s
74
+ end
75
+
76
+ def initialize(key, command, line)
77
+ @line = line
78
+ @disabled = key.strip[0] == "#"
79
+ @key = key.gsub(/\A#+/, "")
80
+ @command = command
81
+ end
82
+ end
83
+
84
+ def disabled(refresh=false)
85
+ return @processes.select { |key,process| process.disabled? } unless refresh || @processes.nil? || @processes.empty?
86
+ reload.select { |key,process| process.disabled? }
87
+ end
88
+
89
+ def enabled(refresh=false)
90
+ return @processes.select { |key,process| process.enabled? } unless refresh || @processes.nil? || @processes.empty?
91
+ reload.select { |key,process| process.enabled? }
92
+ end
93
+
94
+ def processes(refresh=false)
95
+ return @processes unless refresh || @processes.nil? || @processes.empty?
96
+ reload
97
+ end
98
+
99
+ def process_exists?(key)
100
+ processes.keys.include?(key.to_s)
101
+ end
102
+
103
+ def process(key)
104
+ processes.values.select { |p| p.key.to_s == key.to_s }.first
105
+ end
106
+
107
+ def write
108
+ processes.values.each { |process| lines[process.line] = process.to_s}
109
+ open('w') do |pfile|
110
+ lines.each do |line|
111
+ pfile.write "#{line}\n"
112
+ end
113
+ end
114
+ reload
115
+ end
116
+ alias_method :save, :write
117
+
118
+ def reload
119
+ @processes = Processes.new(self)
120
+ return @processes unless exists?
121
+
122
+ read do |line,l|
123
+ if line.match(/\A[#]*[a-z0-9_]+:\s*.*\Z/)
124
+ parr = line.strip.split(":")
125
+ key = parr.slice!(0)
126
+ command = parr.join(":").strip
127
+ process = Process.new(key, command, l)
128
+ @processes[process.key] = process
129
+ end
130
+ end
131
+ @processes
132
+ end
133
+
134
+ def unlink
135
+ super
136
+ reload
137
+ end
138
+
139
+ def initialize(path)
140
+ super
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,44 @@
1
+ require 'yaml'
2
+
3
+ module Greenhouse
4
+ module Resources
5
+ class ProjectsFile
6
+ include FileResource
7
+
8
+ def projects(refresh=false)
9
+ return @projects unless refresh || @projects.nil? || @projects.empty?
10
+ reload
11
+ end
12
+
13
+ def write
14
+ open('w') do |pfile|
15
+ #pfile.write @projects.to_yaml.gsub("!ruby/symbol ", ":").sub("---","").split("\n").map(&:rstrip).join("\n").strip
16
+ @projects.each do |name,project|
17
+ pfile.write "#{name}:\n"
18
+ project.each do |key,val|
19
+ pfile.write " #{key}: #{val.to_s}\n"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ alias_method :save, :write
25
+
26
+ def reload
27
+ @projects = {}
28
+ return @projects unless exists?
29
+ @projects = YAML::load_file(path)
30
+ @projects ||= {}
31
+ @projects
32
+ end
33
+
34
+ def unlink
35
+ super
36
+ reload
37
+ end
38
+
39
+ def initialize(path)
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,10 @@
1
+ module Greenhouse
2
+ module Resources
3
+ end
4
+ end
5
+
6
+ require 'greenhouse/resources/file_resource'
7
+ require 'greenhouse/resources/procfile'
8
+ require 'greenhouse/resources/projects_file'
9
+ require 'greenhouse/resources/ignore_file'
10
+ require 'greenhouse/resources/dotenv_file'
@@ -0,0 +1,36 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ class Argument
4
+ attr_reader :value, :valid, :summary
5
+
6
+ def value=(val)
7
+ raise "Invalid value for `#{key}` flag: '#{val}'" if (!@valid.nil? && !@valid.include?(val)) && (!val.nil? && !val.empty?)
8
+ @value = val
9
+ end
10
+
11
+ def key
12
+ @keys.is_a?(Array) ? @keys[0] : @keys
13
+ end
14
+
15
+ def keys
16
+ @keys.is_a?(Array) ? @keys : [@keys]
17
+ end
18
+
19
+ protected
20
+
21
+ def initialize(keys, *args)
22
+ @keys = (keys.is_a?(String) && keys.match(/,?\s/) ? keys.gsub(/,?\s+/, " ").split(" ") : keys)
23
+
24
+ val = args.slice!(0) if %w(String Symbol Integer).include?(args[0].class.name)
25
+
26
+ if args.length > 0 && args[0].is_a?(Hash)
27
+ opts = args.slice!(0)
28
+ @valid = (opts[:valid].is_a?(Array) ? opts[:valid].map(&:to_s) : opts[:valid].to_s) if opts.has_key?(:valid)
29
+ @summary = opts[:summary] if opts.has_key?(:summary)
30
+ end
31
+
32
+ self.value = val
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ class Arguments < Array
4
+
5
+ def to_s
6
+ map do |arg|
7
+ #if arg.valid.nil? || arg.valid.empty?
8
+ "[#{arg.keys.join(", ")}]"
9
+ #else
10
+ # "[#{arg.keys.join(", ")} = (#{arg.valid.join("|")})]"
11
+ #end
12
+ end.join(" ")
13
+ end
14
+
15
+ def to_help
16
+ map do |arg|
17
+ " #{"%-#{sort { |a,b| a.keys.join(", ").length <=> b.keys.join(", ").length }.last.keys.join(", ").length + 2}s" % arg.keys.join(", ")}# #{arg.summary}"
18
+ end.join("\n")
19
+ end
20
+
21
+ protected
22
+
23
+ def initialize
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ class InvalidArgument < Exception
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,109 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ module Script
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def self.extended(base)
11
+ end
12
+
13
+ def run
14
+ @script ||= new
15
+ raise "You have not defined a `run` method for your script." unless @script.respond_to?(:run)
16
+ @script.run
17
+ end
18
+
19
+ def validate_arguments(val=nil)
20
+ return validate_arguments? if val.nil?
21
+ @validate_arguments = val
22
+ end
23
+
24
+ def validate_arguments?
25
+ @validate_arguments = true if @validate_arguments.nil?
26
+ @validate_arguments
27
+ end
28
+
29
+ def valid_argument(arg)
30
+ @valid_args ||= Arguments.new
31
+ if arg.is_a?(Argument)
32
+ @valid_args << arg
33
+ elsif arg.is_a?(Hash)
34
+ @valid_args << Argument.new(arg.keys.first.to_s, arg.values.first)
35
+ elsif arg.is_a?(Array)
36
+ @valid_args << Argument.new(arg[0].to_s, (arg.length > 1 ? arg[1] : []))
37
+ else
38
+ @valid_args << Argument.new(arg.to_s)
39
+ end
40
+ @valid_args.last
41
+ end
42
+
43
+ def valid_arguments(*args)
44
+ @valid_args ||= Arguments.new
45
+ return @valid_args if args.empty?
46
+
47
+ args.each { |arg| valid_argument(arg) }
48
+ @valid_args
49
+ end
50
+
51
+ def project_argument(proj)
52
+ @valid_projs ||= Arguments.new
53
+ if proj.is_a?(Argument)
54
+ @valid_projs << proj
55
+ elsif proj.is_a?(Hash)
56
+ @valid_projs << Argument.new(proj.keys.first.to_s, proj.values.first)
57
+ elsif proj.is_a?(Array)
58
+ @valid_projs << Argument.new(proj[0].to_s, (proj.length > 1 ? proj[1] : []))
59
+ else
60
+ @valid_projs << Argument.new(proj.to_s)
61
+ end
62
+ @valid_projs.last
63
+ end
64
+
65
+ def project_arguments(*projs)
66
+ @valid_projs ||= Arguments.new
67
+ return @valid_projs if projs.empty?
68
+
69
+ projs.each { |proj| project_argument(proj) }
70
+ @valid_projs
71
+ end
72
+
73
+ def arguments(*args)
74
+ @arguments ||= nil
75
+ return @arguments unless @arguments.nil?
76
+ @arguments = Arguments.new
77
+ args.each_with_index do |arg,a|
78
+ argarr = arg.split("=")
79
+ argkey = argarr.slice!(0)
80
+
81
+ if !valid_arguments.concat(project_arguments).map(&:keys).any? { |keys| keys.include?(argkey) } && !arg.match(/\A(-)+[a-z0-9\-]=?.*\Z/i) && (a > 0 && args[a-1].match(/\A(-)+[a-z0-9\-]=?.*\Z/i)) && !@arguments.empty?
82
+ @arguments.last.value = arg
83
+ next
84
+ end
85
+
86
+ if validate_arguments?
87
+ raise InvalidArgument, "Invalid Argument: #{arg}" unless valid_arguments.concat(project_arguments).map(&:keys).any? { |keys| keys.include?(argkey) }
88
+ @arguments << valid_arguments.concat(project_arguments).select { |varg| varg.keys.include?(argkey) }.first
89
+ else
90
+ valid_arg = valid_arguments.concat(project_arguments).select { |varg| varg.keys.include?(argkey) }.first
91
+ @arguments << (valid_arg || Argument.new(argkey))
92
+ end
93
+ @arguments.last.value = argarr.join("=") unless argarr.empty?
94
+ end
95
+ @arguments
96
+ end
97
+ end
98
+
99
+ module InstanceMethods
100
+ %w(arguments valid_arguments project_arguments).each do |method|
101
+ define_method method do |*args|
102
+ self.class.send method, *args
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,4 @@
1
+ require 'greenhouse/scripts/invalid_argument'
2
+ require 'greenhouse/scripts/argument'
3
+ require 'greenhouse/scripts/arguments'
4
+ require 'greenhouse/scripts/script'
@@ -0,0 +1,57 @@
1
+ module Greenhouse
2
+ module Tasks
3
+ class AddProject
4
+ include Task
5
+
6
+ def prompt_for_project
7
+ remote = nil
8
+ print "Enter a git remote to add a project (leave blank to skip): "
9
+ remote = STDIN.gets.chomp.downcase
10
+ return if remote.empty?
11
+ project = Projects::Project.new(remote.match(/([^\/]*)\.git/)[1], {remote: remote})
12
+
13
+ if Projects::projects_file.projects.keys.include?(project.name) || Projects::projects_file.projects.values.map { |p| p['git'].downcase }.include?(project.repository.remote.downcase)
14
+ puts "\e[31mCannot add project. Another project with the same name already exists.\e[0m"
15
+ # TODO prompt to replace it?
16
+ # would need to probably remove the project, remove procs from procfile, resync project, reconfig, etc.
17
+ return
18
+ end
19
+
20
+ print "Enter a custom title for this project (leave blank for default) [#{project.title}]: "
21
+ title = STDIN.gets.chomp
22
+ project.title = title unless title.empty?
23
+
24
+ print "Is this project a 'gem', rails 'application', rails 'engine' or other type of project (leave blank to skip)?: "
25
+ type = STDIN.gets.chomp.downcase
26
+ type = 'application' if type == 'app' # hacky :/
27
+ unless type.empty?
28
+ classname = "::Greenhouse::Projects::#{type.singularize.camelize}"
29
+ if defined?(classname.constantize)
30
+ project = classname.constantize.new(project.name, {remote: project.repository.remote, title: project.title})
31
+ puts "Configuring #{project.title} as #{type == 'gem' ? 'a' : 'an'} #{type}"
32
+ end
33
+ end
34
+
35
+ project
36
+ end
37
+
38
+ def add_project(project)
39
+ Projects::projects_file.projects[project.name] = {'git' => project.repository.remote}
40
+ Projects::projects_file.projects[project.name]['title'] = project.title unless project.title == project.name.camelize
41
+ Projects::projects_file.projects[project.name]['type'] = project.class.name.underscore.split("/").last unless project.class == Projects::Project
42
+
43
+ Projects::projects_file.write
44
+
45
+ puts "Added \e[36m#{project.title}\e[0m to the ecosystem."
46
+ project
47
+ end
48
+
49
+ def perform
50
+ project = prompt_for_project
51
+ return if project.nil?
52
+
53
+ add_project(project)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,22 @@
1
+ module Greenhouse
2
+ module Tasks
3
+ class GenerateProcfile
4
+ include Task
5
+
6
+ def perform
7
+ Projects::applications.each do |app|
8
+ next unless app.procfile.exists?
9
+ app.procfile.reload
10
+
11
+ if app.procfile.processes.keys.length == 1
12
+ Projects::procfile.processes[app.name] = "#{app.name}: greenhouse launch #{app.name} #{app.procfile.processes.keys.first}" unless Projects::procfile.processes.has_key?(app.name)
13
+ else
14
+ app.procfile.processes.keys.each { |process| Projects::procfile.processes["#{app.name}_#{process}"] = "#{app.name}_#{process}: greenhouse launch #{app.name} #{process}" unless Projects::procfile.processes.has_key?("#{app.name}_#{process}") }
15
+ end
16
+ end
17
+ Projects::procfile.write
18
+ end
19
+
20
+ end
21
+ end
22
+ end