vendorificator 0.0.1

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 (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"