stove 1.1.2 → 2.0.0.beta.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +16 -0
- data/README.md +41 -29
- data/Rakefile +15 -0
- data/bin/bake +1 -2
- data/features/actions/bump.feature +22 -0
- data/features/actions/changelog.feature +45 -0
- data/features/actions/dev.feature +18 -0
- data/features/actions/upload.feature +48 -0
- data/features/plugins/git.feature +24 -0
- data/features/rake.feature +1 -2
- data/features/step_definitions/cli_steps.rb +1 -27
- data/features/step_definitions/{community_site_steps.rb → community_steps.rb} +9 -5
- data/features/step_definitions/config_steps.rb +24 -0
- data/features/step_definitions/cookbook_steps.rb +28 -6
- data/features/step_definitions/cucumber_steps.rb +12 -0
- data/features/step_definitions/git_steps.rb +10 -7
- data/features/support/env.rb +12 -28
- data/features/support/stove/git.rb +48 -0
- data/lib/stove.rb +102 -19
- data/lib/stove/actions/base.rb +21 -0
- data/lib/stove/actions/bump.rb +25 -0
- data/lib/stove/actions/changelog.rb +71 -0
- data/lib/stove/actions/dev.rb +22 -0
- data/lib/stove/actions/finish.rb +8 -0
- data/lib/stove/actions/start.rb +7 -0
- data/lib/stove/actions/upload.rb +27 -0
- data/lib/stove/cli.rb +107 -79
- data/lib/stove/community.rb +124 -0
- data/lib/stove/config.rb +62 -13
- data/lib/stove/cookbook.rb +76 -238
- data/lib/stove/cookbook/metadata.rb +16 -11
- data/lib/stove/error.rb +13 -107
- data/lib/stove/filter.rb +59 -0
- data/lib/stove/jira.rb +74 -30
- data/lib/stove/middlewares/chef_authentication.rb +60 -0
- data/lib/stove/middlewares/exceptions.rb +17 -0
- data/lib/stove/mixins/filterable.rb +11 -0
- data/lib/stove/mixins/insideable.rb +13 -0
- data/lib/stove/mixins/instanceable.rb +23 -0
- data/lib/stove/mixins/loggable.rb +32 -0
- data/lib/stove/mixins/optionable.rb +41 -0
- data/lib/stove/mixins/validatable.rb +7 -0
- data/lib/stove/packager.rb +23 -22
- data/lib/stove/plugins/base.rb +35 -0
- data/lib/stove/plugins/git.rb +71 -0
- data/lib/stove/plugins/github.rb +108 -0
- data/lib/stove/plugins/jira.rb +72 -0
- data/lib/stove/rake_task.rb +56 -37
- data/lib/stove/runner.rb +84 -0
- data/lib/stove/util.rb +56 -0
- data/lib/stove/validator.rb +67 -0
- data/lib/stove/version.rb +1 -1
- data/locales/en.yml +231 -0
- data/stove.gemspec +11 -11
- metadata +85 -67
- data/features/changelog.feature +0 -22
- data/features/cli.feature +0 -11
- data/features/devodd.feature +0 -19
- data/features/git.feature +0 -34
- data/features/upload.feature +0 -40
- data/lib/stove/community_site.rb +0 -85
- data/lib/stove/formatter.rb +0 -7
- data/lib/stove/formatter/base.rb +0 -32
- data/lib/stove/formatter/human.rb +0 -9
- data/lib/stove/formatter/silent.rb +0 -10
- data/lib/stove/git.rb +0 -82
- data/lib/stove/github.rb +0 -43
- data/lib/stove/logger.rb +0 -56
- data/lib/stove/uploader.rb +0 -64
- data/spec/support/community_site.rb +0 -33
- data/spec/support/git.rb +0 -52
@@ -0,0 +1,12 @@
|
|
1
|
+
# These are steps that should really exist in cucumber, but they don't...
|
2
|
+
When /^the environment variable "(.+)" is "(.+)"/ do |variable, value|
|
3
|
+
set_env(variable, value)
|
4
|
+
end
|
5
|
+
|
6
|
+
When /^the environment variable "(.+)" is unset$/ do |variable|
|
7
|
+
set_env(variable, nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
Then /^it should (pass|fail) with "(.+)"$/ do |pass_fail, partial|
|
11
|
+
self.__send__("assert_#{pass_fail}ing_with", partial)
|
12
|
+
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
Given /^the remote repository has additional commits/ do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
git
|
6
|
-
|
2
|
+
cmd = [
|
3
|
+
'cd "' + fake_git_remote + '"',
|
4
|
+
'touch myfile.txt',
|
5
|
+
'git add --force myfile.txt',
|
6
|
+
'git commit --message "Add new file"',
|
7
|
+
].join(' && ')
|
8
|
+
|
9
|
+
%x|#{cmd}|
|
7
10
|
end
|
8
11
|
|
9
|
-
Then /^the git remote
|
12
|
+
Then /^the git remote should( not)? have the commit "(.+)"$/ do |negate, message|
|
10
13
|
commits = git_commits(fake_git_remote)
|
11
14
|
|
12
15
|
if negate
|
@@ -16,7 +19,7 @@ Then /^the git remote will( not)? have the commit "(.+)"$/ do |negate, message|
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
|
-
Then /^the git remote
|
22
|
+
Then /^the git remote should( not)? have the tag "(.+)"$/ do |negate, tag|
|
20
23
|
tags = git_tags(fake_git_remote)
|
21
24
|
|
22
25
|
if negate
|
data/features/support/env.rb
CHANGED
@@ -1,40 +1,24 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
1
3
|
require 'aruba/api'
|
2
4
|
require 'aruba/cucumber'
|
3
|
-
require '
|
5
|
+
require 'cucumber/rspec/doubles'
|
4
6
|
require 'rspec/expectations'
|
7
|
+
|
8
|
+
require 'community_zero/rspec'
|
9
|
+
CommunityZero::RSpec.start
|
10
|
+
Before { CommunityZero::RSpec.reset! }
|
11
|
+
|
5
12
|
require 'stove'
|
6
13
|
|
7
|
-
|
8
|
-
require_relative '../../spec/support/git'
|
14
|
+
require File.expand_path('../stove/git', __FILE__)
|
9
15
|
|
10
16
|
World(Aruba::Api)
|
11
|
-
World(Stove::
|
12
|
-
|
13
|
-
Stove.set_formatter(:silent)
|
14
|
-
Stove::Config.instance_variable_set(:@instance, {
|
15
|
-
'jira_username' => 'default',
|
16
|
-
'jira_password' => 'default',
|
17
|
-
'github_usernmae' => 'default',
|
18
|
-
'github_password' => 'default',
|
19
|
-
'opscode_username' => 'stove',
|
20
|
-
'opscode_pem_file' => File.expand_path(File.join(__FILE__, '..', 'stove.pem')),
|
21
|
-
})
|
22
|
-
Stove::RSpec::CommunitySite.start(port: 3390)
|
23
|
-
Stove::CommunitySite.base_uri(Stove::RSpec::CommunitySite.server_url)
|
24
|
-
Stove::CommunitySite.http_uri(Stove::RSpec::CommunitySite.server_url)
|
17
|
+
World(Stove::Git)
|
25
18
|
|
26
19
|
Before do
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
Before('~@spawn') do
|
32
|
-
Aruba::InProcess.main_class = Stove::Cli
|
33
|
-
Aruba.process = Aruba::InProcess
|
34
|
-
end
|
35
|
-
|
36
|
-
Before('@spawn') do
|
37
|
-
Aruba.process = Aruba::SpawnProcess
|
20
|
+
FileUtils.rm_rf(tmp_path)
|
21
|
+
@aruba_timeout_seconds = 15
|
38
22
|
end
|
39
23
|
|
40
24
|
# The path to Aruba's "stuff"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Stove
|
4
|
+
module Git
|
5
|
+
def git_init(path = Dir.pwd)
|
6
|
+
cmd = [
|
7
|
+
'cd "' + path + '"',
|
8
|
+
'git init .',
|
9
|
+
'git add --all',
|
10
|
+
'git commit --message "Initial commit"',
|
11
|
+
'git remote add origin file://' + fake_git_remote,
|
12
|
+
'git push --quiet --force origin master',
|
13
|
+
].join(' && ')
|
14
|
+
|
15
|
+
%x|#{cmd}|
|
16
|
+
end
|
17
|
+
|
18
|
+
def fake_git_remote
|
19
|
+
path = File.expand_path(File.join(tmp_path, 'remote.git'))
|
20
|
+
return path if File.exists?(path)
|
21
|
+
|
22
|
+
FileUtils.mkdir_p(path)
|
23
|
+
cmd = [
|
24
|
+
'cd "' + path + '"',
|
25
|
+
'git init .',
|
26
|
+
'git config receive.denyCurrentBranch ignore',
|
27
|
+
'git config receive.denyNonFastforwards true',
|
28
|
+
'git config core.sharedrepository 1',
|
29
|
+
].join(' && ')
|
30
|
+
|
31
|
+
%x|#{cmd}|
|
32
|
+
|
33
|
+
path
|
34
|
+
end
|
35
|
+
|
36
|
+
def git_shas(path)
|
37
|
+
%x|cd "#{path}" && git log --oneline|.split("\n").map { |line| line.split(/\s+/, 2).first.strip } rescue []
|
38
|
+
end
|
39
|
+
|
40
|
+
def git_commits(path)
|
41
|
+
%x|cd "#{path}" && git log --oneline|.split("\n").map { |line| line.split(/\s+/, 2).last.strip } rescue []
|
42
|
+
end
|
43
|
+
|
44
|
+
def git_tags(path)
|
45
|
+
%x|cd "#{path}" && git tag --list|.split("\n").map(&:strip) rescue []
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/stove.rb
CHANGED
@@ -1,27 +1,110 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'log4r'
|
4
|
+
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
|
5
|
+
|
1
6
|
module Stove
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
autoload :Config, 'stove/config'
|
8
|
+
autoload :Community, 'stove/community'
|
9
|
+
autoload :Cookbook, 'stove/cookbook'
|
10
|
+
autoload :Cli, 'stove/cli'
|
11
|
+
autoload :Error, 'stove/error'
|
12
|
+
autoload :Filter, 'stove/filter'
|
13
|
+
autoload :JIRA, 'stove/jira'
|
14
|
+
autoload :Mash, 'stove/mash'
|
15
|
+
autoload :Packager, 'stove/packager'
|
16
|
+
autoload :Runner, 'stove/runner'
|
17
|
+
autoload :Util, 'stove/util'
|
18
|
+
autoload :Validator, 'stove/validator'
|
19
|
+
autoload :VERSION, 'stove/version'
|
20
|
+
|
21
|
+
module Action
|
22
|
+
autoload :Base, 'stove/actions/base'
|
23
|
+
autoload :Bump, 'stove/actions/bump'
|
24
|
+
autoload :Changelog, 'stove/actions/changelog'
|
25
|
+
autoload :Dev, 'stove/actions/dev'
|
26
|
+
autoload :Finish, 'stove/actions/finish'
|
27
|
+
autoload :Start, 'stove/actions/start'
|
28
|
+
autoload :Upload, 'stove/actions/upload'
|
29
|
+
end
|
30
|
+
|
31
|
+
module Middleware
|
32
|
+
autoload :ChefAuthentication, 'stove/middlewares/chef_authentication'
|
33
|
+
autoload :Exceptions, 'stove/middlewares/exceptions'
|
34
|
+
end
|
35
|
+
|
36
|
+
module Mixin
|
37
|
+
autoload :Filterable, 'stove/mixins/filterable'
|
38
|
+
autoload :Insideable, 'stove/mixins/insideable'
|
39
|
+
autoload :Instanceable, 'stove/mixins/instanceable'
|
40
|
+
autoload :Loggable, 'stove/mixins/loggable'
|
41
|
+
autoload :Optionable, 'stove/mixins/optionable'
|
42
|
+
autoload :Validatable, 'stove/mixins/validatable'
|
43
|
+
end
|
44
|
+
|
45
|
+
module Plugin
|
46
|
+
autoload :Base, 'stove/plugins/base'
|
47
|
+
autoload :Git, 'stove/plugins/git'
|
48
|
+
autoload :GitHub, 'stove/plugins/github'
|
49
|
+
autoload :JIRA, 'stove/plugins/jira'
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# A constant to represent an unset value. +nil+ is too generic and doesn't
|
54
|
+
# allow users to specify a value as +nil+. Using this constant, we can
|
55
|
+
# safely create +set_or_return+-style methods.
|
56
|
+
#
|
57
|
+
# @return [Object]
|
58
|
+
#
|
59
|
+
UNSET_VALUE = Object.new
|
60
|
+
|
61
|
+
#
|
62
|
+
# The User-Agent to use for HTTP requests
|
63
|
+
#
|
64
|
+
# @return [String]
|
65
|
+
#
|
66
|
+
USER_AGENT = "Stove #{VERSION}"
|
17
67
|
|
18
68
|
class << self
|
19
|
-
|
20
|
-
|
69
|
+
#
|
70
|
+
# The source root of the ChefAPI gem. This is useful when requiring files
|
71
|
+
# that are relative to the root of the project.
|
72
|
+
#
|
73
|
+
# @return [Pathname]
|
74
|
+
#
|
75
|
+
def root
|
76
|
+
@root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
21
77
|
end
|
22
78
|
|
23
|
-
|
24
|
-
|
79
|
+
#
|
80
|
+
# The current log level for the entire application.
|
81
|
+
#
|
82
|
+
# @return [Integer]
|
83
|
+
#
|
84
|
+
def log_level
|
85
|
+
Log4r::Logger.global.level
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Set the global log level.
|
90
|
+
#
|
91
|
+
# @example Set the log level to warn
|
92
|
+
# Stove.log_level = :warn
|
93
|
+
#
|
94
|
+
# @param [String, Symbol] id
|
95
|
+
# the log level to set
|
96
|
+
#
|
97
|
+
def log_level=(id)
|
98
|
+
level = Log4r.const_get(id.to_s.upcase)
|
99
|
+
raise NameError unless level.is_a?(Integer)
|
100
|
+
|
101
|
+
Log4r::Logger.global.level = level
|
102
|
+
rescue NameError
|
103
|
+
$stderr.puts "ERROR `#{id}' is not a valid Log Level!"
|
25
104
|
end
|
26
105
|
end
|
27
106
|
end
|
107
|
+
|
108
|
+
require 'i18n'
|
109
|
+
I18n.enforce_available_locales = true
|
110
|
+
I18n.load_path << Dir[Stove.root.join('locales', '*.yml').to_s]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Stove
|
2
|
+
class Action::Base
|
3
|
+
extend Mixin::Loggable
|
4
|
+
extend Mixin::Optionable
|
5
|
+
extend Mixin::Validatable
|
6
|
+
|
7
|
+
option :id
|
8
|
+
option :description
|
9
|
+
|
10
|
+
attr_reader :cookbook
|
11
|
+
attr_reader :options
|
12
|
+
|
13
|
+
def initialize(cookbook, options = {})
|
14
|
+
@cookbook, @options = cookbook, options
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
raise Error::AbstractMethod.new(method: 'Action::Base#run')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Stove
|
2
|
+
class Action::Bump < Action::Base
|
3
|
+
id 'bump'
|
4
|
+
description 'Perform a version bump the local version automatically'
|
5
|
+
|
6
|
+
validate(:changed) do
|
7
|
+
cookbook.version != options[:version]
|
8
|
+
end
|
9
|
+
|
10
|
+
validate(:incremented) do
|
11
|
+
version = Gem::Version.new(options[:version])
|
12
|
+
Gem::Requirement.new("> #{cookbook.version}").satisfied_by?(version)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
log.info('Performing version bump')
|
17
|
+
log.debug("Version is currently #{cookbook.version}")
|
18
|
+
log.debug("Bumped version is #{options[:version]}")
|
19
|
+
|
20
|
+
cookbook.bump(options[:version])
|
21
|
+
|
22
|
+
log.debug("Version is now #{cookbook.version}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Stove
|
2
|
+
class Action::Changelog < Action::Base
|
3
|
+
id 'changelog'
|
4
|
+
description 'Generate and prompt for a CHANGELOG'
|
5
|
+
|
6
|
+
validate(:exists) do
|
7
|
+
File.exists?('CHANGELOG.md')
|
8
|
+
end
|
9
|
+
|
10
|
+
validate(:format) do
|
11
|
+
lines = File.read('CHANGELOG.md')
|
12
|
+
lines.match(/^[\w\s]+\n=+(.*\n)+v[0-9\.]+(\ \(.+\))?\n\-+/)
|
13
|
+
end
|
14
|
+
|
15
|
+
validate(:editor) do
|
16
|
+
!ENV['EDITOR'].nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
log.info('Generating new Changelog')
|
21
|
+
log.debug("Generated changeset:\n#{default_changeset}")
|
22
|
+
|
23
|
+
# Open a file prompt for changes
|
24
|
+
prompt_for_changeset
|
25
|
+
|
26
|
+
log.debug("New changeset:\n#{cookbook.changeset}")
|
27
|
+
|
28
|
+
# Write the new changelog to disk
|
29
|
+
path = File.join(cookbook.path, 'CHANGELOG.md')
|
30
|
+
contents = File.readlines(path)
|
31
|
+
index = contents.find_index { |line| line =~ /^(--)+/ }
|
32
|
+
|
33
|
+
log.debug("Writing changelog at `#{path}', index #{index}")
|
34
|
+
|
35
|
+
contents.insert(index - 2, "\n" + cookbook.changeset + "\n\n")
|
36
|
+
|
37
|
+
File.open(path, 'w') { |file| file.write(contents.join('')) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def prompt_for_changeset
|
41
|
+
tempfile = Tempfile.new(["#{cookbook.name}-changeset-#{Time.now}", '.md'])
|
42
|
+
tempfile.write(default_changeset)
|
43
|
+
tempfile.rewind
|
44
|
+
|
45
|
+
# Shell out to the default editor
|
46
|
+
system %Q|$EDITOR "#{tempfile.path}"|
|
47
|
+
|
48
|
+
# Save the resulting changes back to the cookbook object
|
49
|
+
cookbook.changeset = File.read(tempfile.path).strip
|
50
|
+
|
51
|
+
# Cleanup
|
52
|
+
tempfile.close
|
53
|
+
tempfile.unlink
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_changeset
|
57
|
+
return @default_changeset if @default_changeset
|
58
|
+
|
59
|
+
header = "v#{cookbook.version} (#{Time.now.to_date})"
|
60
|
+
|
61
|
+
contents = []
|
62
|
+
contents << header
|
63
|
+
contents << '-'*header.length
|
64
|
+
contents << cookbook.changeset || 'Enter CHANGELOG entries here'
|
65
|
+
contents << ''
|
66
|
+
|
67
|
+
@default_changeset = contents.join("\n")
|
68
|
+
@default_changeset
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Stove
|
2
|
+
class Action::Dev < Action::Base
|
3
|
+
id 'dev'
|
4
|
+
description 'Bump a minor version release for development purposes'
|
5
|
+
|
6
|
+
def run
|
7
|
+
log.info('Bumping for development release')
|
8
|
+
log.debug("Version is currently #{cookbook.version}")
|
9
|
+
log.debug("Bumped version is #{dev_version}")
|
10
|
+
|
11
|
+
cookbook.bump(dev_version)
|
12
|
+
|
13
|
+
log.debug("Version is now #{cookbook.version}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def dev_version
|
17
|
+
split = cookbook.version.split('.').map(&:to_i)
|
18
|
+
split[2] += 1
|
19
|
+
split.join('.')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Stove
|
2
|
+
class Action::Upload < Action::Base
|
3
|
+
id 'upload'
|
4
|
+
description 'Upload the cookbook to the community site'
|
5
|
+
|
6
|
+
validate(:configuration) do
|
7
|
+
Config.has_key?(:community)
|
8
|
+
end
|
9
|
+
|
10
|
+
validate(:username) do
|
11
|
+
Config[:community].has_key?(:username)
|
12
|
+
end
|
13
|
+
|
14
|
+
validate(:key) do
|
15
|
+
Config[:community].has_key?(:key)
|
16
|
+
end
|
17
|
+
|
18
|
+
validate(:category) do
|
19
|
+
!cookbook.category.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
log.info('Uploading to the Chef community site')
|
24
|
+
Community.upload(cookbook)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|