dandelion 0.3.15 → 0.4.0.beta2

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +1 -1
  6. data/README.md +15 -26
  7. data/Rakefile +4 -8
  8. data/bin/dandelion +4 -3
  9. data/dandelion.gemspec +23 -20
  10. data/lib/dandelion.rb +26 -10
  11. data/lib/dandelion/adapter.rb +45 -0
  12. data/lib/dandelion/{backend → adapter}/ftp.rb +22 -17
  13. data/lib/dandelion/adapter/noop.rb +14 -0
  14. data/lib/dandelion/{backend → adapter}/s3.rb +14 -15
  15. data/lib/dandelion/{backend → adapter}/sftp.rb +29 -16
  16. data/lib/dandelion/change.rb +11 -0
  17. data/lib/dandelion/changeset.rb +49 -0
  18. data/lib/dandelion/cli.rb +127 -0
  19. data/lib/dandelion/command.rb +26 -92
  20. data/lib/dandelion/command/deploy.rb +54 -41
  21. data/lib/dandelion/command/status.rb +14 -13
  22. data/lib/dandelion/config.rb +36 -0
  23. data/lib/dandelion/deployer.rb +53 -0
  24. data/lib/dandelion/diff.rb +62 -0
  25. data/lib/dandelion/tree.rb +22 -0
  26. data/lib/dandelion/utils.rb +13 -0
  27. data/lib/dandelion/version.rb +2 -2
  28. data/lib/dandelion/workspace.rb +71 -0
  29. data/spec/dandelion/adapter_spec.rb +42 -0
  30. data/spec/dandelion/change_spec.rb +17 -0
  31. data/spec/dandelion/changeset_spec.rb +73 -0
  32. data/spec/dandelion/command/deploy_spec.rb +111 -0
  33. data/spec/dandelion/command/status_spec.rb +4 -0
  34. data/spec/dandelion/command_spec.rb +70 -0
  35. data/spec/dandelion/config_spec.rb +15 -0
  36. data/spec/dandelion/deployer_spec.rb +65 -0
  37. data/spec/dandelion/diff_spec.rb +54 -0
  38. data/spec/dandelion/tree_spec.rb +15 -0
  39. data/spec/dandelion/workspace_spec.rb +77 -0
  40. data/{test/test_git.git → spec/fixtures/repo.git}/HEAD +0 -0
  41. data/{test/test_git.git → spec/fixtures/repo.git}/config +1 -0
  42. data/{test/test_git.git → spec/fixtures/repo.git}/description +0 -0
  43. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/applypatch-msg.sample +0 -0
  44. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/commit-msg.sample +0 -0
  45. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/post-update.sample +0 -0
  46. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/pre-applypatch.sample +0 -0
  47. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/pre-commit.sample +6 -2
  48. data/spec/fixtures/repo.git/hooks/pre-push.sample +53 -0
  49. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/pre-rebase.sample +0 -0
  50. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/prepare-commit-msg.sample +0 -0
  51. data/{test/test_git.git → spec/fixtures/repo.git}/hooks/update.sample +1 -1
  52. data/{test/test_git.git → spec/fixtures/repo.git}/info/exclude +0 -0
  53. data/spec/fixtures/repo.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 +0 -0
  54. data/spec/fixtures/repo.git/objects/34/e64fe350f3ea80c989cdac7a99c2adb8574fca +0 -0
  55. data/spec/fixtures/repo.git/objects/3d/9b743acb4a84dd99002d2c6f3fcf1a47e9f06b +0 -0
  56. data/spec/fixtures/repo.git/objects/4e/44973d41d33bf5342037f56497efe0a9604d25 +0 -0
  57. data/{test/test_git.git → spec/fixtures/repo.git}/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 +0 -0
  58. data/spec/fixtures/repo.git/objects/6c/a0f54491390579ce9438ec89c64c6b3499683a +0 -0
  59. data/spec/fixtures/repo.git/objects/8a/e33865a630c5d141c8a498f0c0166ff240b433 +0 -0
  60. data/{test/test_git.git → spec/fixtures/repo.git}/objects/90/2dce0535b19f0c15ac8407fc4468256ad672d7 +0 -0
  61. data/spec/fixtures/repo.git/objects/c3/9af82404cc4267b1ba5f4b4437a511e0776abb +0 -0
  62. data/spec/fixtures/repo.git/objects/c8/85b3f693ed6e2926971ef75680f41b318072ae +0 -0
  63. data/spec/fixtures/repo.git/objects/d8/7cbcba0e2ede0752bdafc5938da35546803ba5 +0 -0
  64. data/spec/fixtures/repo.git/objects/e2/89ff1e2729839759dbd6fe99b6e35880910c7c +0 -0
  65. data/{test/test_git.git → spec/fixtures/repo.git}/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  66. data/{test/test_git.git → spec/fixtures/repo.git}/objects/ea/41dba10b54a794284e0be009a11f0ff3716a28 +0 -0
  67. data/spec/fixtures/repo.git/objects/ee/314a31b622b027c10981acaed7903a3607dbd4 +0 -0
  68. data/spec/fixtures/repo.git/objects/f6/66b137794d56880bab05e8fd256713a8fccf92 +0 -0
  69. data/spec/fixtures/repo.git/refs/heads/master +1 -0
  70. data/spec/spec_helper.rb +28 -0
  71. metadata +119 -127
  72. data/lib/dandelion/application.rb +0 -73
  73. data/lib/dandelion/backend.rb +0 -54
  74. data/lib/dandelion/deployment.rb +0 -173
  75. data/lib/dandelion/git.rb +0 -123
  76. data/test/fixtures/diff +0 -3
  77. data/test/fixtures/ls_tree +0 -5
  78. data/test/test_diff_deployment.rb +0 -122
  79. data/test/test_ftp.rb +0 -49
  80. data/test/test_git.git/hooks/post-commit.sample +0 -8
  81. data/test/test_git.git/hooks/post-receive.sample +0 -15
  82. data/test/test_git.git/objects/0c/a605e9f0f1d42ce8193ac36db11ec3cc9efc08 +0 -0
  83. data/test/test_git.git/objects/11/bada4e36fd065c8d1d3ca97b8dffa496c8e021 +0 -0
  84. data/test/test_git.git/objects/88/d4480861346093048e08ce8dcc577d8aa69379 +0 -1
  85. data/test/test_git.git/objects/a6/394b3e8a82b76b0dd5b6b317f489dfe22426a6 +0 -0
  86. data/test/test_git.git/objects/a6/5140d5ec9f47064f614ecf8e43776baa5c0c11 +0 -0
  87. data/test/test_git.git/objects/f5/5f3c44c89e5d215fbaaef9d33563117fe0b61b +0 -1
  88. data/test/test_git.git/objects/ff/1f1d4bd0c99e1c9cca047c46b2194accf89504 +0 -4
  89. data/test/test_git.git/refs/heads/master +0 -1
  90. data/test/test_git.rb +0 -50
  91. data/test/test_sftp.rb +0 -54
@@ -1,54 +0,0 @@
1
- require 'tempfile'
2
-
3
- module Dandelion
4
- module Backend
5
- class MissingFileError < StandardError; end
6
- class UnsupportedSchemeError < StandardError; end
7
-
8
- class MissingDependencyError < StandardError
9
- attr_reader :gems
10
-
11
- def initialize(gems)
12
- @gems = gems
13
- end
14
- end
15
-
16
- class Base
17
- class << self
18
- @@backends = {}
19
-
20
- def create(config)
21
- Dir.glob(File.join(File.dirname(__FILE__), 'backend', '*.rb')) { |file| require file }
22
- raise UnsupportedSchemeError unless @@backends.include?(config['scheme'])
23
- begin
24
- @@backends[config['scheme']].new(config)
25
- rescue LoadError
26
- raise MissingDependencyError.new(@@backends[config['scheme']].gem_list)
27
- end
28
- end
29
-
30
- def scheme(scheme)
31
- @@backends[scheme] = self
32
- end
33
-
34
- def gems(*gems)
35
- @gems = gems
36
- end
37
-
38
- def gem_list
39
- @gems
40
- end
41
- end
42
-
43
- protected
44
-
45
- def temp(file, data)
46
- tmp = Tempfile.new(file.gsub('/', '.'))
47
- tmp << data
48
- tmp.flush
49
- yield(tmp.path)
50
- tmp.close
51
- end
52
- end
53
- end
54
- end
@@ -1,173 +0,0 @@
1
- require 'dandelion/git'
2
-
3
- module Dandelion
4
- module Deployment
5
- class RemoteRevisionError < StandardError; end
6
- class FastForwardError < StandardError; end
7
-
8
- class Deployment
9
- class << self
10
- def create(repo, backend, options)
11
- begin
12
- DiffDeployment.new(repo, backend, options)
13
- rescue RemoteRevisionError
14
- FullDeployment.new(repo, backend, options)
15
- end
16
- end
17
- end
18
-
19
- def initialize(repo, backend, options = {})
20
- @repo = repo
21
- @backend = backend
22
- @options = { :exclude => [], :additional => [], :revision => 'HEAD', :revision_file => '.revision', :local_path => '' }.merge(options)
23
- @tree = Git::Tree.new(@repo, @options[:revision], @options[:local_path])
24
-
25
- if @options[:dry]
26
- # Stub out the destructive backend methods
27
- def @backend.write(file, data); end
28
- def @backend.delete(file); end
29
- end
30
- end
31
-
32
- def local_revision
33
- @tree.revision
34
- end
35
-
36
- def remote_revision
37
- nil
38
- end
39
-
40
- def write_revision
41
- @backend.write(@options[:revision_file], local_revision)
42
- end
43
-
44
- def validate
45
- begin
46
- raise FastForwardError if fast_forwardable
47
- rescue Grit::Git::CommandFailed
48
- end
49
- end
50
-
51
- def log
52
- Dandelion.logger
53
- end
54
-
55
- def deploy_additional
56
- if @options[:additional].nil? || @options[:additional].empty?
57
- log.debug("No additional files to deploy")
58
- return
59
- end
60
-
61
- @options[:additional].each do |file|
62
- local_path = file
63
- remote_path = file
64
-
65
- if file.is_a?(Hash)
66
- local_path, remote_path = file.first
67
- end
68
-
69
- log.debug("Uploading additional file: #{local_path} -> #{remote_path}")
70
- @backend.write(remote_path, IO.read(local_path))
71
- end
72
- end
73
-
74
- protected
75
-
76
- def exclude_file?(file)
77
- @options[:exclude].map { |e| file.start_with?(e) }.any? unless @options[:exclude].nil?
78
- end
79
-
80
- private
81
-
82
- def fast_forwardable
83
- !@repo.git.native(:cherry, {:raise => true, :timeout => false}).empty?
84
- end
85
- end
86
-
87
- class DiffDeployment < Deployment
88
- def initialize(repo, backend, options = {})
89
- super(repo, backend, options)
90
- @diff = Git::Diff.new(@repo, read_remote_revision, @options[:revision], @options[:local_path])
91
- end
92
-
93
- def remote_revision
94
- @diff.from_revision
95
- end
96
-
97
- def deploy
98
- if !revisions_match? && any?
99
- deploy_changed
100
- deploy_deleted
101
- else
102
- log.debug("No changes to deploy")
103
- end
104
-
105
- deploy_additional
106
-
107
- unless revisions_match?
108
- write_revision
109
- end
110
- end
111
-
112
- def deploy_changed
113
- @diff.changed.each do |file|
114
- if exclude_file?(file)
115
- log.debug("Skipping file: #{file}")
116
- else
117
- if data = @tree.show(file)
118
- log.debug("Uploading file: #{file}")
119
- @backend.write(file, data)
120
- end
121
- end
122
- end
123
- end
124
-
125
- def deploy_deleted
126
- @diff.deleted.each do |file|
127
- if exclude_file?(file)
128
- log.debug("Skipping file: #{file}")
129
- else
130
- log.debug("Deleting file: #{file}")
131
- @backend.delete(file)
132
- end
133
- end
134
- end
135
-
136
- def any?
137
- @diff.changed.any? || @diff.deleted.any?
138
- end
139
-
140
- def revisions_match?
141
- remote_revision == local_revision
142
- end
143
-
144
- private
145
-
146
- def read_remote_revision
147
- begin
148
- @backend.read(@options[:revision_file]).chomp
149
- rescue Backend::MissingFileError
150
- raise RemoteRevisionError
151
- end
152
- end
153
- end
154
-
155
- class FullDeployment < Deployment
156
- def deploy
157
- @tree.files.each do |file|
158
- if exclude_file?(file)
159
- log.debug("Skipping file: #{file}")
160
- else
161
- if data = @tree.show(file)
162
- log.debug("Uploading file: #{file}")
163
- @backend.write(file, data)
164
- end
165
- end
166
- end
167
-
168
- deploy_additional
169
- write_revision
170
- end
171
- end
172
- end
173
- end
data/lib/dandelion/git.rb DELETED
@@ -1,123 +0,0 @@
1
- require 'grit'
2
-
3
- module Dandelion
4
- module Git
5
- class DiffError < StandardError; end
6
- class RevisionError < StandardError; end
7
-
8
- class Repo < Grit::Repo
9
- def initialize(dir)
10
- super(dir)
11
- end
12
- end
13
-
14
- class Diff
15
- attr_reader :from_revision, :to_revision
16
-
17
- @files = nil
18
-
19
- def initialize(repo, from_revision, to_revision, local_path)
20
- @repo = repo
21
- @local_path = local_path
22
- @from_revision = revision_string(from_revision)
23
- @to_revision = revision_string(to_revision)
24
-
25
- begin
26
- @files = parse(diff)
27
- rescue Grit::Git::CommandFailed
28
- raise DiffError
29
- end
30
- end
31
-
32
- def changed
33
- @files.to_a.select { |f| ['A', 'C', 'M'].include?(f.last) }.map { |f| f.first }
34
- end
35
-
36
- def deleted
37
- @files.to_a.select { |f| 'D' == f.last }.map { |f| f.first }
38
- end
39
-
40
- private
41
-
42
- def diff
43
- @repo.git.native(:diff, { :name_status => true, :raise => true }, @from_revision, @to_revision)
44
- end
45
-
46
- def parse(diff)
47
- files = {}
48
- diff.split("\n").each do |line|
49
- status, file = line.split("\t")
50
- files[file] = status
51
- end
52
- files
53
- end
54
-
55
- def revision_string(revision)
56
- if @local_path.nil? || @local_path.empty?
57
- revision
58
- else
59
- "#{revision}:#{@local_path}"
60
- end
61
- end
62
- end
63
-
64
- class Tree
65
- def initialize(repo, revision, local_path)
66
- @repo = repo
67
- @commit = @repo.commit(revision)
68
- @revision = revision
69
- @local_path = local_path
70
- raise RevisionError if @commit.nil?
71
- @tree = @commit.tree
72
- end
73
-
74
- def files
75
- @repo.git.native(:ls_tree, { :name_only => true, :full_tree => true, :r => true }, revision_string).split("\n")
76
- end
77
-
78
- def show(file)
79
- blob = @tree / file_path(file)
80
- if blob.is_a?(Grit::Submodule)
81
- puts "#{file} is a submodule, ignoring."
82
- else
83
- blob.data
84
- end
85
- end
86
-
87
- def revision
88
- @commit.sha
89
- end
90
-
91
- private
92
-
93
- def file_path(file)
94
- if local_path?
95
- File.join(@local_path, file)
96
- else
97
- file
98
- end
99
- end
100
-
101
- def revision_string
102
- if local_path?
103
- "#{@revision}:#{@local_path}"
104
- else
105
- @revision
106
- end
107
- end
108
-
109
- def local_path?
110
- !@local_path.nil? && !@local_path.empty?
111
- end
112
- end
113
- end
114
- end
115
-
116
- # Grit does not support Ruby 2.0 right now
117
- class String
118
- if ((defined? RUBY_VERSION) && (RUBY_VERSION[0..2] == "1.9" || RUBY_VERSION[0].to_i >= 2))
119
- def getord(offset); self[offset].ord; end
120
- else
121
- alias :getord :[]
122
- end
123
- end
data/test/fixtures/diff DELETED
@@ -1,3 +0,0 @@
1
- M baz/foo
2
- A foo
3
- D foobar
@@ -1,5 +0,0 @@
1
- bar
2
- baz/bar
3
- baz/foo
4
- baz/foo/bar
5
- foo
@@ -1,122 +0,0 @@
1
- require 'dandelion'
2
- require 'dandelion/deployment'
3
- require 'test/unit'
4
-
5
- def fixture(name)
6
- File.read(File.join(File.dirname(__FILE__), 'fixtures', name))
7
- end
8
-
9
- # Mock classes
10
-
11
- class MockGit
12
- def native(cmd, options = {}, *args, &block)
13
- if cmd == :ls_tree
14
- fixture('ls_tree')
15
- elsif cmd == :diff
16
- fixture('diff')
17
- end
18
- end
19
- end
20
-
21
- class MockFile
22
- attr_reader :data
23
-
24
- def initialize(data)
25
- @data = data
26
- end
27
- end
28
-
29
- class MockTree
30
- def /(file)
31
- MockFile.new('bar')
32
- end
33
- end
34
-
35
- class MockCommit
36
- def initialize(revision)
37
- @revision = revision
38
- end
39
-
40
- def tree
41
- MockTree.new
42
- end
43
-
44
- def sha
45
- @revision
46
- end
47
- end
48
-
49
- class MockRepo
50
- def commit(revision)
51
- MockCommit.new(revision)
52
- end
53
-
54
- def git
55
- MockGit.new
56
- end
57
- end
58
-
59
- class MockBackend
60
- attr_reader :reads, :writes, :deletes
61
-
62
- def initialize(remote_revision)
63
- @reads = {'.revision' => remote_revision}
64
- @writes = {}
65
- @deletes = []
66
- end
67
-
68
- def read(file)
69
- @reads[file]
70
- end
71
-
72
- def write(file, data)
73
- @writes[file] = data
74
- end
75
-
76
- def delete(file)
77
- @deletes << file
78
- end
79
- end
80
-
81
- # Tests
82
-
83
- class TestDiffDeployment < Test::Unit::TestCase
84
- def setup
85
- Dandelion.logger.level = Logger::FATAL
86
- @head_revision = '0ca605e9f0f1d42ce8193ac36db11ec3cc9efc08'
87
- @remote_revision = 'ff1f1d4bd0c99e1c9cca047c46b2194accf89504'
88
- @repo = MockRepo.new
89
- @backend = MockBackend.new(@remote_revision)
90
- @diff_deployment = Dandelion::Deployment::DiffDeployment.new(@repo, @backend, :revision => @head_revision)
91
- end
92
-
93
- def test_diff_deployment_local_revision
94
- assert_equal @head_revision, @diff_deployment.local_revision
95
- end
96
-
97
- def test_diff_deployment_remote_revision
98
- assert_equal @remote_revision, @diff_deployment.remote_revision
99
- end
100
-
101
- def test_diff_deployment_write_revision
102
- @diff_deployment.write_revision
103
- assert_equal @head_revision, @backend.writes['.revision']
104
- end
105
-
106
- def test_diff_deployment_revisions_match
107
- assert !@diff_deployment.revisions_match?
108
- end
109
-
110
- def test_diff_deployment_any
111
- assert @diff_deployment.any?
112
- end
113
-
114
- def test_diff_deployment_deploy
115
- @diff_deployment.deploy
116
- assert_equal 3, @backend.writes.length
117
- assert_equal 'bar', @backend.writes['foo']
118
- assert_equal 'bar', @backend.writes['baz/foo']
119
- assert_equal @head_revision, @backend.writes['.revision']
120
- assert_equal ['foobar'], @backend.deletes
121
- end
122
- end