vendorificator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +19 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE +22 -0
  5. data/README.md +45 -0
  6. data/Rakefile +29 -0
  7. data/bin/vendor +4 -0
  8. data/bin/vendorify +6 -0
  9. data/examples/Vendorfile +25 -0
  10. data/features/chef_cookbook.feature +44 -0
  11. data/features/deprecated.feature +17 -0
  12. data/features/fixtures/git/testrepo/HEAD +1 -0
  13. data/features/fixtures/git/testrepo/config +7 -0
  14. data/features/fixtures/git/testrepo/description +1 -0
  15. data/features/fixtures/git/testrepo/hooks/applypatch-msg.sample +15 -0
  16. data/features/fixtures/git/testrepo/hooks/commit-msg.sample +24 -0
  17. data/features/fixtures/git/testrepo/hooks/post-update.sample +8 -0
  18. data/features/fixtures/git/testrepo/hooks/pre-applypatch.sample +14 -0
  19. data/features/fixtures/git/testrepo/hooks/pre-commit.sample +50 -0
  20. data/features/fixtures/git/testrepo/hooks/pre-rebase.sample +169 -0
  21. data/features/fixtures/git/testrepo/hooks/prepare-commit-msg.sample +36 -0
  22. data/features/fixtures/git/testrepo/hooks/update.sample +128 -0
  23. data/features/fixtures/git/testrepo/info/exclude +6 -0
  24. data/features/fixtures/git/testrepo/info/refs +5 -0
  25. data/features/fixtures/git/testrepo/objects/info/packs +2 -0
  26. data/features/fixtures/git/testrepo/objects/pack/pack-46f7621b6a6b9b1c22dd15c08d457dfedf76e55f.idx +0 -0
  27. data/features/fixtures/git/testrepo/objects/pack/pack-46f7621b6a6b9b1c22dd15c08d457dfedf76e55f.pack +0 -0
  28. data/features/fixtures/git/testrepo/packed-refs +6 -0
  29. data/features/fixtures/git/testrepo/refs/heads/.sentinel +0 -0
  30. data/features/fixtures/git/testrepo/refs/tags/.sentinel +0 -0
  31. data/features/fixtures/vcr_cassettes/vendorificator.yml +2375 -0
  32. data/features/git.feature +12 -0
  33. data/features/needed.feature +16 -0
  34. data/features/smoke.feature +14 -0
  35. data/features/status.feature +47 -0
  36. data/features/step_definitions/basic.rb +52 -0
  37. data/features/step_definitions/git.rb +39 -0
  38. data/features/step_definitions/vendorificator.rb +27 -0
  39. data/features/support/env.rb +32 -0
  40. data/features/support/transform_pattern.rb +12 -0
  41. data/features/support/world_git.rb +40 -0
  42. data/features/support/world_runs.rb +90 -0
  43. data/features/tarball.feature +63 -0
  44. data/features/tarball_edit.feature +15 -0
  45. data/features/vendor.feature +16 -0
  46. data/lib/vendorificator/cli.rb +233 -0
  47. data/lib/vendorificator/config.rb +72 -0
  48. data/lib/vendorificator/hooks/chef_cookbook.rb +23 -0
  49. data/lib/vendorificator/repo.rb +69 -0
  50. data/lib/vendorificator/vendor/archive.rb +90 -0
  51. data/lib/vendorificator/vendor/chef_cookbook.rb +58 -0
  52. data/lib/vendorificator/vendor/git.rb +47 -0
  53. data/lib/vendorificator/vendor.rb +260 -0
  54. data/lib/vendorificator/version.rb +3 -0
  55. data/lib/vendorificator.rb +9 -0
  56. data/vendorificator.gemspec +30 -0
  57. metadata +321 -0
@@ -0,0 +1,12 @@
1
+ Feature: Git-based vendor module
2
+
3
+ Scenario:
4
+ Given a repository with following Vendorfile:
5
+ """ruby
6
+ git "file://#{ENV['FIXTURES_DIR']}/git/testrepo"
7
+ """
8
+ When I run "vendor"
9
+ Then following has been conjured:
10
+ | Name | testrepo |
11
+ | Version | 10e9ac58c77bc229d8c59a5b4eb7422916453148 |
12
+ | With file | test/alias.c |
@@ -0,0 +1,16 @@
1
+ Feature: a vendor module is downloaded only if needed
2
+
3
+ Scenario: already downloaded tarball
4
+ Given a repository with following Vendorfile:
5
+ """ruby
6
+ archive :testrepo, :version => '0.1',
7
+ :url => 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1.tar.gz'
8
+ """
9
+ When I run "vendor"
10
+ Then I'm on "master" branch
11
+ And command output includes /module\s+testrepo/
12
+ And command output includes "testrepo-0.1.tar.gz"
13
+ Then I run "vendor"
14
+ And command output includes /module\s+testrepo/
15
+ And command output includes /up to date\s+testrepo/
16
+ And command output does not include "testrepo-0.1.tar.gz"
@@ -0,0 +1,14 @@
1
+ Feature: smoke test of the test suite
2
+ In order to trust my tests,
3
+ As the developer of Vendorificator,
4
+ I want to make sure that test environment itself does not emit smoke.
5
+
6
+ Scenario: The default environment
7
+ Given nothing in particular
8
+ When nothing happens
9
+ Then the README file exists
10
+ And git repository is clean
11
+ And git history has one commit
12
+ And I'm on "master" branch
13
+ And no other branch exists
14
+
@@ -0,0 +1,47 @@
1
+ Feature: Module status
2
+
3
+ The `status` subcommand statuss all known modules and their status.
4
+
5
+ Background:
6
+ Given a repository with following Vendorfile:
7
+ """ruby
8
+ vendor 'generated', :version => '0.23' do |v|
9
+ File.open('README', 'w') { |f| f.puts "Hello, World!" }
10
+ File.open('VERSION', 'w') { |f| f.puts v.version }
11
+ end
12
+ """
13
+
14
+ Scenario: status new module
15
+ When I run "vendor status"
16
+ Then command output includes /new\s+generated\/0.23/
17
+
18
+ Scenario: status up-to-date module
19
+ When I run "vendor"
20
+ And I run "vendor status"
21
+ Then command output includes /up to date\s+generated\/0.23/
22
+
23
+ Scenario: status outdated modules
24
+ When I run "vendor"
25
+ And I change Vendorfile to:
26
+ """ruby
27
+ vendor 'generated', :version => '0.42' do |v|
28
+ File.open('README', 'w') { |f| f.puts "Hello, Updated, World!" }
29
+ File.open('VERSION', 'w') { |f| f.puts v.version }
30
+ end
31
+ """
32
+ And I run "vendor status"
33
+ Then command output includes /outdated\s+generated\/0.42/
34
+
35
+ Scenario: Module's dependencies are statused if they are known
36
+ When I change Vendorfile to:
37
+ """ruby
38
+ require 'vendorificator/vendor/chef_cookbook'
39
+ chef_cookbook 'memcached'
40
+ """
41
+ And I run "vendor status"
42
+ Then command output includes /new\s+memcached/
43
+ And command output does not include "runit"
44
+ When I run "vendor"
45
+ And I run "vendor status"
46
+ Then command output includes /up to date\s+memcached/
47
+ And command output includes /up to date\s+runit/
@@ -0,0 +1,52 @@
1
+ Given /^nothing in particular$/ do
2
+ nil # NOP
3
+ end
4
+
5
+ When /^nothing happens$/ do
6
+ nil # NOP
7
+ end
8
+
9
+ Then /^file "(.*?)" exists$/ do |path|
10
+ assert { File.exists?(path) }
11
+ end
12
+
13
+ Then /^file "(.*?)" does not exist$/ do |path|
14
+ deny { File.exists?(path) }
15
+ end
16
+
17
+ Then /^the README file exists$/ do
18
+ step 'file "README" exists'
19
+ end
20
+
21
+ Then /^file "(.*?)" reads "(.*?)"$/ do |path, text|
22
+ assert { File.read(path).strip == text.strip }
23
+ end
24
+
25
+ Given /^a repository with following Vendorfile:$/ do |string|
26
+ commit_file('Vendorfile', string)
27
+ end
28
+
29
+ When /^I change Vendorfile to:$/ do |string|
30
+ commit_file('Vendorfile', string, "Updated Vendorfile")
31
+ end
32
+
33
+ When /^I try to run "(.*?)"$/ do |command_string|
34
+ run command_string
35
+ end
36
+
37
+ When /^I run "(.*?)"$/ do |command_string|
38
+ step "I try to run \"#{command_string}\""
39
+ assert { command_succeeded }
40
+ end
41
+
42
+ Then /the command has failed/ do
43
+ deny { command_succeeded(false) }
44
+ end
45
+
46
+ Then /^command (output|stdout|stderr) includes (#{PATTERN})$/ do |stream, pat|
47
+ assert { command_output(stream) =~ pat }
48
+ end
49
+
50
+ Then /^command (output|stdout|stderr) does not include (#{PATTERN})$/ do |stream, pat|
51
+ deny { command_output(stream) =~ pat }
52
+ end
@@ -0,0 +1,39 @@
1
+ Then /^git repository is clean$/ do
2
+ assert { repo_clean? }
3
+ end
4
+
5
+ Then /^git history has one commit$/ do
6
+ assert { git.log.count == 1 }
7
+ end
8
+
9
+ Then /^I\'m on "(.*?)" branch$/ do |expected_branch|
10
+ assert { branch == expected_branch }
11
+ end
12
+
13
+ Then /^no other branch exists$/ do
14
+ assert { branches.length == 1 }
15
+ end
16
+
17
+ Then /^branch "(.*?)" exists$/ do |branch_name|
18
+ assert { branches.include?(branch_name) }
19
+ end
20
+
21
+ Then /^branch "(.*?)" does not exist$/ do |branch_name|
22
+ deny { branches.include?(branch_name) }
23
+ end
24
+
25
+ Then /^tag "(.*?)" exists$/ do |tag_name|
26
+ assert { tags.include?(tag_name) }
27
+ end
28
+
29
+ Then /^tag "(.*?)" does not exist$/ do |tag_name|
30
+ deny { tags.include?(tag_name) }
31
+ end
32
+
33
+ Then /^tag matching (#{PATTERN}) exists$/ do |pat|
34
+ assert { tags.any?{|t| t=~pat} }
35
+ end
36
+
37
+ Then /^tag matching (#{PATTERN}) does not exist$/ do |pat|
38
+ deny { tags.any?{|t| t=~pat} }
39
+ end
@@ -0,0 +1,27 @@
1
+ Then /^(?:the )?following has( not)? been conjured:$/ do |not_p, table|
2
+ exists_p = not_p ? "does not exist" : "exists"
3
+
4
+ step "I'm on \"master\" branch"
5
+
6
+ table.transpose.hashes.each do |mod|
7
+ step "branch \"vendor/#{mod['Name']}\" #{exists_p}"
8
+
9
+ if mod['Version']
10
+ step "tag \"vendor/#{mod['Name']}/#{mod['Version']}\" #{exists_p}"
11
+ else
12
+ step "tag matching /^vendor\\/#{Regexp.quote(mod['Name']).gsub('/', '\\/')}\\// #{exists_p}"
13
+ end
14
+
15
+ if mod['With file']
16
+ mod['With file'].lines.each do |path|
17
+ step "file \"vendor/#{mod['Name']}/#{path.strip}\" #{exists_p}"
18
+ end
19
+ end
20
+
21
+ if mod['Without file']
22
+ mod['Without file'].lines.each do |path|
23
+ step "file \"vendor/#{mod['Name']}/#{path.strip}\" does not exist"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'tmpdir'
4
+
5
+ require 'wrong'
6
+
7
+ World(Wrong)
8
+
9
+ # Run each test in a temporary directory, initialized as a git repository
10
+ FileUtils::mkdir_p 'tmp'
11
+
12
+ Before do
13
+ @orig_wd = Dir.getwd
14
+ @tmp_wd = Dir.mktmpdir(nil, 'tmp')
15
+ Dir.chdir(@tmp_wd)
16
+
17
+ commit_file('README', 'Lorem ipsum dolor sit amet')
18
+ end
19
+
20
+ After do |scenario|
21
+ Dir::chdir(@orig_wd)
22
+ if ENV['DEBUG'] || scenario.failed?
23
+ puts "Keeping working directory #{@tmp_wd} for debugging"
24
+ else
25
+ FileUtils::rm_rf(@tmp_wd)
26
+ end
27
+ @tmp_wd = nil
28
+ end
29
+
30
+ ENV['FIXTURES_DIR'] = Pathname.new(__FILE__).
31
+ dirname.join('..', 'fixtures').realpath.to_s
32
+
@@ -0,0 +1,12 @@
1
+ # Matching (#{PATTERN}) will match "foo" or /foo/, and return a
2
+ # regular expression. With quotes, the expression will be escaped.
3
+
4
+ PATTERN = /[\"\/](?:\\.|[^\"\/\\])*[\"\/]/
5
+
6
+ Transform /^\/((?:\\.|[^\/\\])*)\/$/ do |rx|
7
+ Regexp.new(rx)
8
+ end
9
+
10
+ Transform /^\"((?:\\.|[^\"\\])*)\"$/ do |str|
11
+ Regexp.new(Regexp.quote(str))
12
+ end
@@ -0,0 +1,40 @@
1
+ require 'fileutils'
2
+ require 'git'
3
+
4
+ module Vendorificator
5
+ module TestSupport
6
+ module Git
7
+ def git(*args)
8
+ @git ||= {}
9
+ @git[args] ||= ::Git.init(*args)
10
+ end
11
+
12
+ def commit_file(path, contents, message=nil)
13
+ message ||= "Added #{path}"
14
+ FileUtils.mkdir_p(File.dirname(path))
15
+ File.open(path, 'w') { |f| f.puts(contents) }
16
+ git.add(path)
17
+ git.commit(message)
18
+ end
19
+
20
+ def repo_clean?
21
+ # FIXME: How to do that with ruby-git?
22
+ `git status --porcelain` == ""
23
+ end
24
+
25
+ def branch
26
+ git.current_branch
27
+ end
28
+
29
+ def branches
30
+ git.branches.map(&:to_s)
31
+ end
32
+
33
+ def tags
34
+ git.tags.map(&:name)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ World(Vendorificator::TestSupport::Git)
@@ -0,0 +1,90 @@
1
+ require 'mixlib/shellout'
2
+
3
+ class String
4
+ def strip_console_escapes
5
+ self.gsub(/\e\[[^m]{1,5}m/,'')
6
+ end
7
+
8
+ def indent(amount, char=' ')
9
+ prefix = char * amount
10
+ lines.map { |ln| ln =~ /^\s*$/ ? ln : prefix+ln }.join
11
+ end
12
+ end
13
+
14
+ module Vendorificator
15
+ module TestSupport
16
+ module RunsCommands
17
+ def command
18
+ raise RuntimeError, "No command has run yet!" unless @command
19
+ @command
20
+ end
21
+
22
+ def run(*command_args)
23
+ opts = {}
24
+ opts = command_args.pop if command_args.last.is_a?(Hash)
25
+
26
+ # We need to clear out Git environment variables left here by
27
+ # the Git gem.
28
+ opts[:environment] ||= {}
29
+ opts[:environment].merge!(
30
+ 'GIT_DIR' => nil,
31
+ 'GIT_INDEX_FILE' => nil,
32
+ 'GIT_WORK_TREE' => nil)
33
+
34
+ command_args.push opts
35
+ @command = Mixlib::ShellOut.new(*command_args)
36
+
37
+ command.run_command
38
+ print_command_result if ENV['VERBOSE']
39
+ end
40
+
41
+ def command_succeeded(print_failed=true)
42
+ command.error!
43
+ true
44
+ rescue Mixlib::ShellOut::ShellCommandFailed
45
+ print_command_result if print_failed
46
+ false
47
+ end
48
+
49
+ def command_stdout
50
+ command.stdout.strip_console_escapes
51
+ end
52
+
53
+ def command_stderr
54
+ command.stderr.strip_console_escapes
55
+ end
56
+
57
+ # Depending on stream, returns:
58
+ # when 'stdout': command_stdout
59
+ # when 'stderr': command_stderr
60
+ # otherwise: command.stdout + "\n" + command_stderr
61
+ def command_output(stream=nil)
62
+ case stream
63
+ when 'stdout'
64
+ command_stdout
65
+ when 'stderr'
66
+ command_stderr
67
+ else
68
+ "#{command_stdout}\n#{command_stderr}"
69
+ end
70
+ end
71
+
72
+ def print_command_result
73
+ puts <<EOF
74
+
75
+ -------- BEGIN #{command.command.inspect} --------
76
+ Exit status: #{command.exitstatus}
77
+ Execution time: #{command.execution_time}
78
+ Stdout:
79
+ #{command_stdout.indent(4)}
80
+ Stderr:
81
+ #{command_stderr.indent(4)}
82
+ -------- END #{command.command.inspect} --------
83
+
84
+ EOF
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ World(Vendorificator::TestSupport::RunsCommands)
@@ -0,0 +1,63 @@
1
+ Feature: simple tarball module
2
+
3
+ Scenario: just URL as name
4
+ Given a repository with following Vendorfile:
5
+ """ruby
6
+ archive 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1.tar.gz'
7
+ """
8
+ When I run "vendor"
9
+ Then following has been conjured:
10
+ | Name | testrepo-0.1 |
11
+ | Version | testrepo-0.1.tar.gz |
12
+ | With file | test/alias.c |
13
+
14
+ Scenario: URL as keyword
15
+ Given a repository with following Vendorfile:
16
+ """ruby
17
+ archive :testrepo,
18
+ :url => 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1.tar.gz'
19
+ """
20
+ When I run "vendor"
21
+ Then following has been conjured:
22
+ | Name | testrepo |
23
+ | Version | testrepo-0.1.tar.gz |
24
+ | With file | test/alias.c |
25
+
26
+ Scenario: Version & checksum
27
+ Given a repository with following Vendorfile:
28
+ """ruby
29
+ archive :testrepo,
30
+ :url => 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1.tar.gz',
31
+ :version => '0.1',
32
+ :checksum => 'ea207a896f929ffb3a1dfe128332d6134a18edab7c01b97bfb2b1c7eacebe0cb'
33
+ """
34
+ When I run "vendor"
35
+ Then following has been conjured:
36
+ | Name | testrepo |
37
+ | Version | 0.1 |
38
+ | With file | test/alias.c |
39
+
40
+ Scenario: Wrong checksum
41
+ Given a repository with following Vendorfile:
42
+ """ruby
43
+ archive :testrepo,
44
+ :url => 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1.tar.gz',
45
+ :version => '0.1',
46
+ :checksum => 'incorrect'
47
+ """
48
+ When I try to run "vendor"
49
+ Then the command has failed
50
+ Then following has not been conjured:
51
+ | Name | testrepo |
52
+ | With file | test/alias.c |
53
+
54
+ Scenario: Tarball without a root directory
55
+ Given a repository with following Vendorfile:
56
+ """ruby
57
+ archive :testrepo,
58
+ :url => 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1-noroot.tar.gz'
59
+ """
60
+ When I run "vendor"
61
+ Then following has been conjured:
62
+ | Name | testrepo |
63
+ | With file | test/alias.c |
@@ -0,0 +1,15 @@
1
+ Feature: Edit the tarball after downloading
2
+
3
+ Scenario:
4
+ Given a repository with following Vendorfile:
5
+ """ruby
6
+ archive :testrepo,
7
+ :url => 'http://test-assets.3ofcoins.net.s3-website-us-east-1.amazonaws.com/testrepo-0.1.tar.gz' do
8
+ FileUtils::rm Dir['test/archive*.c']
9
+ end
10
+ """
11
+ When I run "vendor"
12
+ Then following has been conjured:
13
+ | Name | testrepo |
14
+ | With file | test/alias.c |
15
+ | Without file | test/archive.c |
@@ -0,0 +1,16 @@
1
+ Feature: bare 'vendor' clause
2
+
3
+ Scenario:
4
+ Given a repository with following Vendorfile:
5
+ """ruby
6
+ vendor 'generated', :version => '0.23' do |v|
7
+ File.open('README', 'w') { |f| f.puts "Hello, World!" }
8
+ File.open('VERSION', 'w') { |f| f.puts v.version }
9
+ end
10
+ """
11
+ When I run "vendor"
12
+ Then the following has been conjured:
13
+ | Name | generated |
14
+ | Version | 0.23 |
15
+ | With file | README |
16
+ And file "vendor/generated/VERSION" reads "0.23"