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.
- checksums.yaml +7 -0
- data/bin/greenhouse +9 -0
- data/lib/greenhouse/cli.rb +88 -0
- data/lib/greenhouse/commands/add.rb +32 -0
- data/lib/greenhouse/commands/command.rb +88 -0
- data/lib/greenhouse/commands/configure.rb +9 -0
- data/lib/greenhouse/commands/help.rb +45 -0
- data/lib/greenhouse/commands/init.rb +93 -0
- data/lib/greenhouse/commands/launch.rb +113 -0
- data/lib/greenhouse/commands/new.rb +42 -0
- data/lib/greenhouse/commands/pull.rb +45 -0
- data/lib/greenhouse/commands/purge.rb +91 -0
- data/lib/greenhouse/commands/push.rb +45 -0
- data/lib/greenhouse/commands/remove.rb +32 -0
- data/lib/greenhouse/commands/start.rb +21 -0
- data/lib/greenhouse/commands/status.rb +50 -0
- data/lib/greenhouse/commands/sync.rb +42 -0
- data/lib/greenhouse/commands.rb +32 -0
- data/lib/greenhouse/projects/application.rb +19 -0
- data/lib/greenhouse/projects/collection.rb +23 -0
- data/lib/greenhouse/projects/engine.rb +6 -0
- data/lib/greenhouse/projects/gem.rb +6 -0
- data/lib/greenhouse/projects/project.rb +77 -0
- data/lib/greenhouse/projects/repository.rb +197 -0
- data/lib/greenhouse/projects.rb +86 -0
- data/lib/greenhouse/resources/dotenv_file.rb +69 -0
- data/lib/greenhouse/resources/file_resource.rb +50 -0
- data/lib/greenhouse/resources/ignore_file.rb +115 -0
- data/lib/greenhouse/resources/procfile.rb +144 -0
- data/lib/greenhouse/resources/projects_file.rb +44 -0
- data/lib/greenhouse/resources.rb +10 -0
- data/lib/greenhouse/scripts/argument.rb +36 -0
- data/lib/greenhouse/scripts/arguments.rb +28 -0
- data/lib/greenhouse/scripts/invalid_argument.rb +6 -0
- data/lib/greenhouse/scripts/script.rb +109 -0
- data/lib/greenhouse/scripts.rb +4 -0
- data/lib/greenhouse/tasks/add_project.rb +57 -0
- data/lib/greenhouse/tasks/generate_procfile.rb +22 -0
- data/lib/greenhouse/tasks/project_status.rb +37 -0
- data/lib/greenhouse/tasks/project_task.rb +363 -0
- data/lib/greenhouse/tasks/pull_project.rb +14 -0
- data/lib/greenhouse/tasks/purge_project.rb +13 -0
- data/lib/greenhouse/tasks/push_project.rb +14 -0
- data/lib/greenhouse/tasks/remove_greenhouse_files.rb +58 -0
- data/lib/greenhouse/tasks/remove_project.rb +15 -0
- data/lib/greenhouse/tasks/sync_project.rb +19 -0
- data/lib/greenhouse/tasks/task.rb +25 -0
- data/lib/greenhouse/tasks.rb +20 -0
- data/lib/greenhouse/version.rb +20 -0
- data/lib/greenhouse.rb +12 -0
- metadata +165 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Commands
|
3
|
+
class Push
|
4
|
+
include Command
|
5
|
+
command_summary "Push local branches for all projects to their git remotes"
|
6
|
+
project_arguments *Projects::projects.map(&:to_arg)
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def usage
|
10
|
+
puts <<USAGE
|
11
|
+
usage: #{::Greenhouse::CLI.command_name} #{command_name} [<project>] #{valid_arguments.to_s}
|
12
|
+
|
13
|
+
Projects:
|
14
|
+
#{project_arguments.to_help}
|
15
|
+
USAGE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def push_all
|
20
|
+
if Projects.projects.empty?
|
21
|
+
puts "No projects defined."
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
Projects.projects.each do |project|
|
26
|
+
Tasks::PushProject.perform(project)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def push_project(project)
|
31
|
+
unless project.exists?
|
32
|
+
puts "Project \e[36m#{project.title}\e[0m does not exist. Try initializing it with `greenhouse init`"
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
Tasks::PushProject.perform(project)
|
37
|
+
end
|
38
|
+
|
39
|
+
def run
|
40
|
+
project = Projects::projects.select { |project| arguments.map(&:key).include?(project.name) }.first
|
41
|
+
project.nil? ? push_all : push_project(project)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Commands
|
3
|
+
class Remove
|
4
|
+
include Command
|
5
|
+
command_summary "Purge a project and remove it from the ecosystem .projects file"
|
6
|
+
project_arguments *Projects::projects.map(&:to_arg)
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def usage
|
10
|
+
puts <<USAGE
|
11
|
+
usage: #{::Greenhouse::CLI.command_name} #{command_name} <project>
|
12
|
+
|
13
|
+
Projects:
|
14
|
+
#{project_arguments.to_help}
|
15
|
+
USAGE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
if arguments.empty?
|
21
|
+
puts "You must provide the name of the project you want to remove from your ecosystem."
|
22
|
+
usage
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
project = Projects::projects.select { |proj| proj.name == arguments[0].key }.first
|
27
|
+
Tasks::PurgeProject.perform(project)
|
28
|
+
Tasks::RemoveProject.perform(project)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Commands
|
3
|
+
class Start
|
4
|
+
include Command
|
5
|
+
|
6
|
+
command_summary "Startup the entire ecosystem of apps using your Procfile (aliases `foreman start`)"
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def usage
|
10
|
+
puts "usage: #{::Greenhouse::CLI.command_name} #{command_name} #{valid_arguments.to_s}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
Dir.chdir(Projects::path) do
|
16
|
+
exec 'foreman start'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Commands
|
3
|
+
class Status
|
4
|
+
include Command
|
5
|
+
command_summary "List projects and their current status"
|
6
|
+
valid_arguments Scripts::Argument.new("-v, --verbose", :summary => "Print out detailed information about project status (local changes, ahead/behind/diverged branches, etc.)")
|
7
|
+
project_arguments *Projects::projects.map(&:to_arg)
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def usage
|
11
|
+
puts <<USAGE
|
12
|
+
usage: #{::Greenhouse::CLI.command_name} #{command_name} [<project>] #{valid_arguments.to_s}
|
13
|
+
|
14
|
+
Arguments:
|
15
|
+
#{valid_arguments.to_help}
|
16
|
+
|
17
|
+
Projects:
|
18
|
+
#{project_arguments.to_help}
|
19
|
+
USAGE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def verbose
|
24
|
+
arguments.map(&:key).include?("-v")
|
25
|
+
end
|
26
|
+
|
27
|
+
def ecosystem_status
|
28
|
+
if Projects::projects.empty?
|
29
|
+
puts "No projects configured."
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "The following projects are configured in your ecosystem: "
|
34
|
+
Projects::projects.each do |project|
|
35
|
+
puts
|
36
|
+
Tasks::ProjectStatus.perform(project, verbose)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def project_status(project)
|
41
|
+
Tasks::ProjectStatus.perform(project, verbose)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run
|
45
|
+
project = Projects::projects.select { |project| arguments.map(&:key).include?(project.name) }.first
|
46
|
+
project.nil? ? ecosystem_status : project_status(project)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Commands
|
3
|
+
class Sync
|
4
|
+
include Command
|
5
|
+
command_summary "Sync all projects with their git remotes"
|
6
|
+
project_arguments *Projects::projects.map(&:to_arg)
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def usage
|
10
|
+
puts <<USAGE
|
11
|
+
usage: #{::Greenhouse::CLI.command_name} #{command_name} [<project>] #{valid_arguments.to_s}
|
12
|
+
|
13
|
+
Projects:
|
14
|
+
#{project_arguments.to_help}
|
15
|
+
USAGE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def sync_all
|
20
|
+
if Projects.projects.empty?
|
21
|
+
puts "No projects defined."
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
Projects.projects.each do |project|
|
26
|
+
Tasks::SyncProject.perform(project)
|
27
|
+
end
|
28
|
+
Tasks::GenerateProcfile.perform
|
29
|
+
end
|
30
|
+
|
31
|
+
def sync_project(project)
|
32
|
+
Tasks::SyncProject.perform(project)
|
33
|
+
Tasks::GenerateProcfile.perform if project.type == 'application'
|
34
|
+
end
|
35
|
+
|
36
|
+
def run
|
37
|
+
project = Projects::projects.select { |project| arguments.map(&:key).include?(project.name) }.first
|
38
|
+
project.nil? ? sync_all : sync_project(project)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Commands
|
3
|
+
def self.commands
|
4
|
+
@commands ||= []
|
5
|
+
@commands
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.exists?(cmd)
|
9
|
+
commands.map(&:command_name).include?(cmd.underscore.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.command(cmd)
|
13
|
+
raise "Command does not exist: #{cmd}" unless exists?(cmd)
|
14
|
+
commands.select { |command| command.command_name == cmd.underscore.to_s }.first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'greenhouse/commands/command'
|
20
|
+
require 'greenhouse/commands/new'
|
21
|
+
require 'greenhouse/commands/init'
|
22
|
+
require 'greenhouse/commands/configure'
|
23
|
+
require 'greenhouse/commands/add'
|
24
|
+
require 'greenhouse/commands/status'
|
25
|
+
require 'greenhouse/commands/launch'
|
26
|
+
require 'greenhouse/commands/start'
|
27
|
+
require 'greenhouse/commands/push'
|
28
|
+
require 'greenhouse/commands/pull'
|
29
|
+
require 'greenhouse/commands/sync'
|
30
|
+
require 'greenhouse/commands/purge'
|
31
|
+
require 'greenhouse/commands/remove'
|
32
|
+
require 'greenhouse/commands/help'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Projects
|
3
|
+
class Application < Project
|
4
|
+
attr_reader :dotenv, :procfile
|
5
|
+
|
6
|
+
def configured?
|
7
|
+
@dotenv.exists?
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def initialize(name, args={})
|
13
|
+
super
|
14
|
+
@procfile = Resources::Procfile.new("#{path}/Procfile")
|
15
|
+
@dotenv = Resources::DotenvFile.new("#{path}/.env")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Projects
|
3
|
+
class Collection < Array
|
4
|
+
protected
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super
|
8
|
+
|
9
|
+
# DEPRECATED - moving this to Projects itself
|
10
|
+
each do |project|
|
11
|
+
meth = project.class.name.pluralize.underscore.split("/").last.to_sym
|
12
|
+
next if respond_to?(meth)
|
13
|
+
|
14
|
+
self.class.instance_eval do
|
15
|
+
define_method meth do
|
16
|
+
select { |proj| proj.class.name.pluralize.underscore.split("/").last.to_sym == meth }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Projects
|
3
|
+
class Project
|
4
|
+
attr_accessor :name, :repository, :title
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_reader :subclasses
|
8
|
+
|
9
|
+
# Keep track of inheriting classes (to use as project "types")
|
10
|
+
def inherited(subclass)
|
11
|
+
(@subclasses ||= [self]) << subclass
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def initialize(name, args={})
|
17
|
+
@name = name
|
18
|
+
@title = args.delete('title') || name.camelize
|
19
|
+
@ignored = (args.has_key?('ignore') ? [args.delete('ignore')] : []).flatten
|
20
|
+
@repository = Repository.new(name, args)
|
21
|
+
@ignore_file = Resources::IgnoreFile.new("#{path}/.ignore")
|
22
|
+
end
|
23
|
+
|
24
|
+
def ignored
|
25
|
+
Projects.ignored.concat(@ignore_file.ignored).concat(@ignored)
|
26
|
+
end
|
27
|
+
|
28
|
+
def chdir(&block)
|
29
|
+
Dir.chdir(path, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return the local path to the project repo
|
33
|
+
def path
|
34
|
+
@repository.path
|
35
|
+
end
|
36
|
+
|
37
|
+
def gemfile
|
38
|
+
return nil unless gemfile?
|
39
|
+
"#{path}/Gemfile"
|
40
|
+
end
|
41
|
+
|
42
|
+
def gemfile?
|
43
|
+
chdir { return File.exists?("Gemfile") }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Check if the repository exists
|
47
|
+
def exists?
|
48
|
+
@repository.exists?
|
49
|
+
end
|
50
|
+
|
51
|
+
def type
|
52
|
+
self.class.name.underscore.split('/').last
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_arg
|
56
|
+
Scripts::Argument.new(name, :summary => "#{title} (#{type.capitalize})")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Go into the local directory and run Bundler
|
60
|
+
def bundle(cmd='install')
|
61
|
+
raise "Directory does not exist: #{path}" unless exists?
|
62
|
+
Dir.chdir(path) do
|
63
|
+
Bundler.with_clean_env do
|
64
|
+
# TODO look into using Bundler to install instead of executing system cmd
|
65
|
+
Greenhouse::CLI::exec "bundle #{cmd.to_s} 2>&1"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Remove the project directory
|
71
|
+
def destroy
|
72
|
+
@repository.destroy # use the repository object to destroy itself/directory
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module Greenhouse
|
2
|
+
module Projects
|
3
|
+
class Repository
|
4
|
+
attr_accessor :local, :remote
|
5
|
+
alias_method :path, :local
|
6
|
+
|
7
|
+
def method_missing(meth, *args)
|
8
|
+
return git.send(meth, *args) if git.respond_to?(meth)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Clone the remote into the local path
|
13
|
+
def clone
|
14
|
+
raise "Repository already exists: #{@local}" if cloned?
|
15
|
+
Git.clone(@remote, @local.split("/").last)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Check if the remote has been cloned locally
|
19
|
+
def cloned?
|
20
|
+
File.exists?(@local) && @git ||= Git.open(@local)
|
21
|
+
end
|
22
|
+
alias_method :exists?, :cloned?
|
23
|
+
|
24
|
+
# Check whether there are any uncommited local changes
|
25
|
+
def changes?(untracked=true)
|
26
|
+
raise "Repository does not exist: #{@local}" unless cloned?
|
27
|
+
!changes(untracked).empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get a list of all local changes (modified, added, deleted & untracked)
|
31
|
+
def changes(include_untracked=true)
|
32
|
+
raise "Repository does not exist: #{@local}" unless cloned?
|
33
|
+
changes = changed.merge(git.status.added).merge(git.status.deleted)
|
34
|
+
changes.merge!(untracked) if include_untracked
|
35
|
+
changes
|
36
|
+
end
|
37
|
+
|
38
|
+
def changed?
|
39
|
+
!changed.empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
def changed
|
43
|
+
git.status.changed.select { |name,file| !git.diff('HEAD', '--').path(name).to_s.empty? }
|
44
|
+
end
|
45
|
+
|
46
|
+
def untracked
|
47
|
+
git.status.untracked.select { |name,file| !name.match(/\Atmp\/.*\Z/) } # temporary hack to avoid untracked tmp files, since they're not being properly ignored(?)
|
48
|
+
end
|
49
|
+
|
50
|
+
def untracked?
|
51
|
+
!untracked.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def staged
|
55
|
+
changed.merge(git.status.added).merge(git.status.deleted).delete_if { |name,file| file.sha_index.empty? || file.sha_index == '0000000000000000000000000000000000000000' }
|
56
|
+
end
|
57
|
+
|
58
|
+
def staged?
|
59
|
+
!staged.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def unstaged
|
63
|
+
changed.merge(untracked).select { |name,file| file.sha_index.empty? || file.sha_index == '0000000000000000000000000000000000000000' }
|
64
|
+
end
|
65
|
+
|
66
|
+
def unstaged?
|
67
|
+
!unstaged.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return the results of `ls-files --others` to list ignored/untracked files
|
71
|
+
def others
|
72
|
+
git.chdir do
|
73
|
+
return `git ls-files --others`.split("\n")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Check whether local branches are synced with the remotes
|
78
|
+
def synced?
|
79
|
+
unsynced.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return any unsynced branches for all remotes
|
83
|
+
def unsynced
|
84
|
+
branches = []
|
85
|
+
git.branches.local.each do |branch|
|
86
|
+
git.remotes.each do |remote|
|
87
|
+
lcommit = git.object(branch.name).log.first
|
88
|
+
rcommit = git.object("#{remote.name}/#{branch.name}").log.first
|
89
|
+
next if lcommit.sha == rcommit.sha
|
90
|
+
branches << [branch, remote]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
branches
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check whether there are unpushed local changes on all branches/remotes
|
97
|
+
def ahead?
|
98
|
+
!ahead.empty?
|
99
|
+
end
|
100
|
+
|
101
|
+
# Return any unpushed local changes on all branches/remotes
|
102
|
+
def ahead
|
103
|
+
unsynced.select do |branch|
|
104
|
+
lbranch = git.object(branch[0].name)
|
105
|
+
rbranch = git.object("#{branch[1].name}/#{branch[0].name}")
|
106
|
+
lcommit = lbranch.log.first
|
107
|
+
rcommit = rbranch.log.first
|
108
|
+
|
109
|
+
!rbranch.log.map(&:sha).include?(lcommit.sha) && lbranch.log.map(&:sha).include?(rcommit.sha)
|
110
|
+
|
111
|
+
#lcommit.date <= rcommit.date
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if there are any unpulled changes on all branches/remotes
|
116
|
+
def behind?
|
117
|
+
!behind.empty?
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return any unpulled changes on all branches/remotes
|
121
|
+
def behind
|
122
|
+
unsynced.select do |branch|
|
123
|
+
lbranch = git.object(branch[0].name)
|
124
|
+
rbranch = git.object("#{branch[1].name}/#{branch[0].name}")
|
125
|
+
lcommit = lbranch.log.first
|
126
|
+
rcommit = rbranch.log.first
|
127
|
+
|
128
|
+
rbranch.log.map(&:sha).include?(lcommit.sha) && !lbranch.log.map(&:sha).include?(rcommit.sha)
|
129
|
+
|
130
|
+
#lcommit.date >= rcommit.date
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def diverged?
|
135
|
+
!diverged.empty?
|
136
|
+
end
|
137
|
+
|
138
|
+
def diverged
|
139
|
+
unsynced.select do |branch|
|
140
|
+
lbranch = git.object(branch[0].name)
|
141
|
+
rbranch = git.object("#{branch[1].name}/#{branch[0].name}")
|
142
|
+
lcommit = lbranch.log.first
|
143
|
+
rcommit = rbranch.log.first
|
144
|
+
|
145
|
+
!rbranch.log.map(&:sha).include?(lcommit.sha) && !lbranch.log.map(&:sha).include?(rcommit.sha)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def up_to_date?
|
150
|
+
!out_of_sync?
|
151
|
+
end
|
152
|
+
|
153
|
+
def out_of_sync?
|
154
|
+
behind? || diverged?
|
155
|
+
end
|
156
|
+
|
157
|
+
def out_of_sync
|
158
|
+
unsynced.select do |branch|
|
159
|
+
lbranch = git.object(branch[0].name)
|
160
|
+
rbranch = git.object("#{branch[1].name}/#{branch[0].name}")
|
161
|
+
lcommit = lbranch.log.first
|
162
|
+
rcommit = rbranch.log.first
|
163
|
+
|
164
|
+
(rbranch.log.map(&:sha).include?(lcommit.sha) && !lbranch.log.map(&:sha).include?(rcommit.sha)) ||
|
165
|
+
(!rbranch.log.map(&:sha).include?(lcommit.sha) && !lbranch.log.map(&:sha).include?(rcommit.sha))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def stash
|
170
|
+
git.chdir { `git stash 2>&1` }
|
171
|
+
end
|
172
|
+
|
173
|
+
def pop_stash
|
174
|
+
git.chdir { `git stash pop 2>&1` }
|
175
|
+
end
|
176
|
+
|
177
|
+
# Remove the local repository
|
178
|
+
def destroy
|
179
|
+
FileUtils.rm_rf @local
|
180
|
+
end
|
181
|
+
|
182
|
+
def git
|
183
|
+
@git ||= Git.open(@local)
|
184
|
+
@git
|
185
|
+
end
|
186
|
+
|
187
|
+
protected
|
188
|
+
|
189
|
+
def initialize(name, args={})
|
190
|
+
raise "A git remote is required." unless args.has_key?(:remote)
|
191
|
+
@local = File.expand_path(args[:local] || name)
|
192
|
+
@remote = args[:remote]# || "git@github.com:Graphicly/#{name}.git"
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'git'
|
3
|
+
require 'greenhouse/projects/repository'
|
4
|
+
require 'greenhouse/projects/collection'
|
5
|
+
require 'greenhouse/projects/project'
|
6
|
+
require 'greenhouse/projects/engine'
|
7
|
+
require 'greenhouse/projects/application'
|
8
|
+
require 'greenhouse/projects/gem'
|
9
|
+
|
10
|
+
module Greenhouse
|
11
|
+
module Projects
|
12
|
+
@@path = nil
|
13
|
+
@@procfile = nil
|
14
|
+
@@ignore_file = nil
|
15
|
+
@@projects_file = nil
|
16
|
+
@@dotenv = nil
|
17
|
+
@@projects = nil
|
18
|
+
|
19
|
+
def self.method_missing(meth, *args)
|
20
|
+
if Project.subclasses.map { |subclass| subclass.name.pluralize.underscore.split("/").last.to_sym }.include?(meth.to_sym)
|
21
|
+
projects.select { |proj| proj.class.name.pluralize.underscore.split("/").last.to_sym == meth.to_sym }
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.projects
|
28
|
+
@@projects = Collection.new
|
29
|
+
return @@projects unless projects_file.exists?
|
30
|
+
|
31
|
+
projects_file.projects.each do |name,project|
|
32
|
+
type = (project.has_key?('type') ? project['type'] : 'project')
|
33
|
+
projargs = project.merge({:remote => (project['remote'] || project['git'])})
|
34
|
+
classname = "Greenhouse::Projects::#{type.singularize.camelize}"
|
35
|
+
@@projects << (defined?(classname.constantize) ? classname.constantize.new(name, projargs) : Greenhouse::Projects::Project.new(name, projargs))
|
36
|
+
end
|
37
|
+
@@projects
|
38
|
+
end
|
39
|
+
|
40
|
+
# Attempts to look for and returns the path of the root projects directory
|
41
|
+
#
|
42
|
+
# Looks up the tree from the current directory, currently checking for a .projects
|
43
|
+
# file (this might change in the future).
|
44
|
+
#
|
45
|
+
# If no projects path is found, the current directory is returned.
|
46
|
+
def self.path
|
47
|
+
return @@path unless @@path.nil?
|
48
|
+
dir = Dir.pwd
|
49
|
+
while dir != "" do
|
50
|
+
if File.exists?("#{dir}/.projects")
|
51
|
+
@@path = dir
|
52
|
+
return @@path
|
53
|
+
end
|
54
|
+
dir = dir.gsub(/\/[^\/]*\Z/,'')
|
55
|
+
end
|
56
|
+
@@path = Dir.pwd # if we haven't found a .projects file, this must be where they want to work
|
57
|
+
@@path
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.ignore_file
|
61
|
+
return @@ignore_file unless @@ignore_file.nil?
|
62
|
+
@@ignore_file = Resources::IgnoreFile.new("#{path}/.ignore")
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.projects_file
|
66
|
+
return @@projects_file unless @@projects_file.nil?
|
67
|
+
@@projects_file = Resources::ProjectsFile.new("#{path}/.projects")
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.procfile
|
71
|
+
return @@procfile unless @@procfile.nil?
|
72
|
+
@@procfile = Resources::Procfile.new("#{path}/Procfile")
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.dotenv
|
76
|
+
return @@dotenv unless @@dotenv.nil?
|
77
|
+
@@dotenv = Resources::DotenvFile.new("#{path}/.env")
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.ignored
|
81
|
+
return [] unless ignore_file.exists?
|
82
|
+
ignore_file.ignored
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|