knife-community 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.
- data/.gitignore +21 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +93 -0
- data/Rakefile +41 -0
- data/features/cli.feature +12 -0
- data/features/support/env.rb +14 -0
- data/knife-community.gemspec +44 -0
- data/lib/chef/knife/community_release.rb +240 -0
- data/lib/knife-community/version.rb +3 -0
- data/spec/spec_helper.rb +2 -0
- metadata +274 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# A Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
9
|
+
|
10
|
+
guard 'cucumber' do
|
11
|
+
watch(%r{^features/.+\.feature$})
|
12
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
13
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
14
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Mike Fiedler
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
knife-community
|
2
|
+
===============
|
3
|
+
[](http://travis-ci.org/miketheman/knife-community)
|
4
|
+
[](https://gemnasium.com/miketheman/knife-community)
|
5
|
+
|
6
|
+
A Knife plugin to assist with deploying completed Chef cookbooks to the Community Site
|
7
|
+
|
8
|
+
Intro
|
9
|
+
-----
|
10
|
+
|
11
|
+
There are sooo many ways to [deliver software][wiki:apppkg].
|
12
|
+
Apt has 'deb', Yum has 'rpm', Node has 'npm', RubyGems has 'gem', Java has 'jar', etc etc etc.
|
13
|
+
|
14
|
+
In The Land of [Chef][chef], the typical unit of shareable software is a 'cookbook'.
|
15
|
+
|
16
|
+
The centralized location for sharing cookbooks is the [Community Site][opcs], and we already have support to download/install these elements, either it be through [knife itself][kcsi], [librarian][libr], and [berkshelf][brks], and there are probably others.
|
17
|
+
|
18
|
+
What we _don't_ have is a good method for cookbook maintainers to contribute back to the Community Site, while semi-enforcing good habits, such as version incrementing, git tags and forming the package correctly.
|
19
|
+
|
20
|
+
Assumptions
|
21
|
+
-----------
|
22
|
+
|
23
|
+
### Basics
|
24
|
+
* You know what Git is
|
25
|
+
* You know what Chef is
|
26
|
+
* You have Push permissions to the remote GitHub repository
|
27
|
+
* You don't already have a perfected workflow that works for you
|
28
|
+
* You want to be a helpful citizen of the community
|
29
|
+
|
30
|
+
### Important
|
31
|
+
* You have **not** incremented the version number in `metadata.rb` - this will do so for you
|
32
|
+
* You have a `name` string defined in your `metadata.rb`, OR your repository name is identical to your cookbook name
|
33
|
+
* You have either committed or staged all changes to be included with this version release. Any uncommitted changed should be `git stash`ed, or stage them to be committed along with the version via `git add`
|
34
|
+
|
35
|
+
Cookbook Release Workflow
|
36
|
+
-------------------------
|
37
|
+
|
38
|
+
Assuming you have made your changes, tested your code thoroughly (one can hope!), all merged into your `master` branch, and are ready to release a new version of your cookbook, here's a flow to follow:
|
39
|
+
|
40
|
+
1. Ensure that the branch is ready to be committed. If there are uncommitted changes, error out.
|
41
|
+
1. Read in the current `metadata.rb`, inspect the `version` string, and increment it to the next tiny version. Override with CLI argument.
|
42
|
+
1. Create a git commit for the `metadata.rb` change.
|
43
|
+
1. Create a git tag with the version number (no leading "v" or the like)
|
44
|
+
1. Push all commits/tags to the set remote, typically like `git push origin master`. Override with `--branch`
|
45
|
+
1. Create a 'package' - effectively a compressed tarball - and upload it to the community site
|
46
|
+
1. Have a beer, or glass of wine - you choose.
|
47
|
+
|
48
|
+
This flow can probably be used for most cookbook maintainers.
|
49
|
+
|
50
|
+
Usage
|
51
|
+
=====
|
52
|
+
|
53
|
+
Invoke
|
54
|
+
------
|
55
|
+
|
56
|
+
knife community release COOKBOOK [X.Y.Z | --remote | --branch | --devodd ]
|
57
|
+
|
58
|
+
Flags
|
59
|
+
-----
|
60
|
+
|
61
|
+
* `X.Y.Z` - String, Version in X.Y.Z format. Manually specify the version.
|
62
|
+
|
63
|
+
If unspecified, increments to the next x.y.Z version
|
64
|
+
|
65
|
+
* `--remote REMOTE` - String, Remote repository to push to. Defaults to `origin`
|
66
|
+
|
67
|
+
* `--branch BRANCHNAME` - String, Branch name. Defaults to `master`
|
68
|
+
|
69
|
+
* `--devodd` - Boolean. If specified, post-release, will bump the minor version to the next odd number, and generate another commit & push (but no tags).
|
70
|
+
|
71
|
+
This is a flow that some adopt by having even-only numbered releases, utilizing the [odd numbered ones for development][wiki:oddver].
|
72
|
+
|
73
|
+
|
74
|
+
Some good ideas while working on a cookbook
|
75
|
+
-------------------------------------------
|
76
|
+
|
77
|
+
Creating a `CHANGELOG.md` that details a short message about any changes included in each release is really helpful to anyone looking at your updated cookbook and seeing if it addresses a problem they have, without delving deeper into the code.
|
78
|
+
|
79
|
+
Updating a `TODO.md` file if there are outstanding known issues, planned work for the next version, etc. A TODO file also helps anyone else in the community try to tackle a problem you haven't figured out or gotten to yet, so they can issue a pull request for your cookbook.
|
80
|
+
|
81
|
+
Follow [Semantic Versioning][semver] when choosing which version number to increment to. Start your cookbook at 0.1.0, and increment from there, until you are confident enough in a 1.0.0 version.
|
82
|
+
|
83
|
+
Test, test, test. And then test again.
|
84
|
+
|
85
|
+
|
86
|
+
[brks]: http://berkshelf.com/
|
87
|
+
[chef]: http://www.opscode.com/chef/
|
88
|
+
[kcsi]: http://wiki.opscode.com/display/chef/Managing+Cookbooks+With+Knife#ManagingCookbooksWithKnife-CookbookSite
|
89
|
+
[libr]: https://github.com/applicationsonline/librarian
|
90
|
+
[opcs]: http://community.opscode.com/
|
91
|
+
[semver]: http://semver.org/
|
92
|
+
[wiki:apppkg]: http://en.wikipedia.org/wiki/List_of_software_package_management_systems#Application-level_package_managers
|
93
|
+
[wiki:oddver]: http://en.wikipedia.org/wiki/Software_versioning#Odd-numbered_versions_for_development_releases
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
task :default => [:features]
|
5
|
+
|
6
|
+
# https://github.com/turboladen/tailor
|
7
|
+
require 'tailor/rake_task'
|
8
|
+
Tailor::RakeTask.new do |task|
|
9
|
+
task.file_set('lib/**/*.rb', 'code') do |style|
|
10
|
+
style.max_line_length 160, level: :warn
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'cucumber/rake/task'
|
15
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
16
|
+
t.cucumber_opts = ['features', '-x']
|
17
|
+
t.cucumber_opts += ['--format pretty']
|
18
|
+
end
|
19
|
+
|
20
|
+
# https://github.com/guard/guard
|
21
|
+
require 'guard'
|
22
|
+
desc "Start up guard, does not exit until told to with 'q'."
|
23
|
+
task :guard do
|
24
|
+
Guard.setup
|
25
|
+
Guard::Dsl.evaluate_guardfile(:guardfile => 'Guardfile')
|
26
|
+
Guard.start
|
27
|
+
end
|
28
|
+
|
29
|
+
# File lib/tasks/notes.rake
|
30
|
+
desc "Find notes in code"
|
31
|
+
task :notes do
|
32
|
+
puts `grep --exclude=Rakefile -r 'OPTIMIZE:\\|FIXME:\\|TODO:' .`
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clean up any artefacts
|
36
|
+
desc "Clean up dev environment cruft like tmp and packages"
|
37
|
+
task :clean do
|
38
|
+
%w{pkg tmp}.each do |subdir|
|
39
|
+
FileUtils.rm_rf(subdir)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: Ensure that the Command Line Interface works as designed
|
2
|
+
In order to operate the knife community release cookbook tool
|
3
|
+
As a Cookbook Maintainer
|
4
|
+
I want to ensure the CLI behaves correctly with different arguments
|
5
|
+
|
6
|
+
Scenario: Running with no arguments produces a failure
|
7
|
+
When I run `knife community release`
|
8
|
+
Then the exit status should be 1
|
9
|
+
|
10
|
+
Scenario: Running with too many arguments produces a failure
|
11
|
+
When I run `knife community release foo bar baz`
|
12
|
+
Then the exit status should be 1
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Set up the environment for testing
|
2
|
+
require 'aruba/cucumber'
|
3
|
+
# require 'aruba-doubles/cucumber'
|
4
|
+
|
5
|
+
# Before do
|
6
|
+
# @dirs = ["tmp/aruba"]
|
7
|
+
# end
|
8
|
+
|
9
|
+
After do |s|
|
10
|
+
# Tell Cucumber to quit after this scenario is done - if it failed.
|
11
|
+
# This is useful to inspect the 'tmp/aruba' directory before any other
|
12
|
+
# steps are executed and clear it out.
|
13
|
+
Cucumber.wants_to_quit = true if s.failed?
|
14
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
chef_version = ENV.key?('CHEF_VERSION') ? "= #{ENV['CHEF_VERSION']}" : ['~> 10']
|
3
|
+
require File.expand_path('../lib/knife-community/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
|
7
|
+
gem.name = "knife-community"
|
8
|
+
gem.summary = %q{A Knife plugin to assist with deploying completed Chef cookbooks to the Community Site}
|
9
|
+
gem.description = %q{The centralized location for sharing cookbooks is the Community Site, this is a process helper to produce a repeatable method for releasing cookbooks.}
|
10
|
+
gem.version = KnifeCommunity::VERSION
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
|
17
|
+
gem.add_dependency 'chef', chef_version
|
18
|
+
|
19
|
+
# OPTIMIZE: Use Mixlib/Shellout until actions are written in pure ruby
|
20
|
+
gem.add_dependency 'mixlib-shellout', '~> 1.1.0'
|
21
|
+
|
22
|
+
# Using Grit to examin git repo status, and interact with a git repo
|
23
|
+
gem.add_dependency 'grit', '~> 2'
|
24
|
+
|
25
|
+
# A good version comparison library
|
26
|
+
gem.add_dependency 'versionomy', '~> 0.4'
|
27
|
+
|
28
|
+
gem.required_ruby_version = '>= 1.9.2'
|
29
|
+
|
30
|
+
gem.add_development_dependency 'rake', '~> 0.9'
|
31
|
+
gem.add_development_dependency 'rspec', '~> 2.11.0'
|
32
|
+
gem.add_development_dependency 'cucumber', '~> 1'
|
33
|
+
gem.add_development_dependency 'aruba', '~> 0.4'
|
34
|
+
gem.add_development_dependency 'tailor', '~> 1.1'
|
35
|
+
gem.add_development_dependency 'travis-lint', '~> 1.4'
|
36
|
+
gem.add_development_dependency 'guard', '~> 1.3'
|
37
|
+
gem.add_development_dependency 'guard-rspec', '~> 1.2'
|
38
|
+
gem.add_development_dependency 'guard-cucumber', '~> 1.2'
|
39
|
+
|
40
|
+
gem.authors = ["Mike Fiedler"]
|
41
|
+
gem.email = ["miketheman@gmail.com"]
|
42
|
+
gem.homepage = "http://miketheman.github.com/knife-community"
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
module KnifeCommunity
|
4
|
+
class CommunityRelease < Chef::Knife
|
5
|
+
|
6
|
+
deps do
|
7
|
+
require 'knife-community/version'
|
8
|
+
require 'mixlib/shellout'
|
9
|
+
require 'chef/config'
|
10
|
+
require 'chef/cookbook_loader'
|
11
|
+
require 'chef/knife/cookbook_site_share'
|
12
|
+
require 'chef/cookbook_site_streaming_uploader'
|
13
|
+
require 'grit'
|
14
|
+
require 'versionomy'
|
15
|
+
require 'json'
|
16
|
+
end
|
17
|
+
|
18
|
+
banner "knife community release COOKBOOK [VERSION] (options)"
|
19
|
+
|
20
|
+
option :cookbook_path,
|
21
|
+
:short => "-o PATH:PATH",
|
22
|
+
:long => "--cookbook-path PATH:PATH",
|
23
|
+
:description => "A colon-separated path to look for cookbooks in",
|
24
|
+
:proc => lambda { |o| o.split(":") }
|
25
|
+
|
26
|
+
option :remote,
|
27
|
+
:short => "-R REMOTE",
|
28
|
+
:long => "--remote REMOTE",
|
29
|
+
:default => "origin",
|
30
|
+
:description => "Remote Git repository to push to"
|
31
|
+
|
32
|
+
option :branch,
|
33
|
+
:short => "-B ",
|
34
|
+
:long => "--branch BRANCH",
|
35
|
+
:default => "master",
|
36
|
+
:description => "Remote Git branch name to push to"
|
37
|
+
|
38
|
+
option :devodd,
|
39
|
+
:long => "--devodd",
|
40
|
+
:boolean => true,
|
41
|
+
:description => "Odd-numbered development cycle. Bump minor version & commit for development"
|
42
|
+
|
43
|
+
def run
|
44
|
+
self.config = Chef::Config.merge!(config)
|
45
|
+
validate_args
|
46
|
+
# Set variables for global use
|
47
|
+
@cookbook = name_args.first
|
48
|
+
@version = Versionomy.parse(name_args.last) if name_args.size > 1
|
49
|
+
|
50
|
+
ui.msg "Starting to validate the envrionment before changing anything..."
|
51
|
+
validate_cookbook_exists
|
52
|
+
validate_repo
|
53
|
+
validate_repo_clean
|
54
|
+
validate_version_sanity
|
55
|
+
validate_no_existing_tag
|
56
|
+
validate_target_remote_branch
|
57
|
+
|
58
|
+
ui.msg "All validation steps have passed, making changes..."
|
59
|
+
set_new_cb_version
|
60
|
+
commit_new_cb_version
|
61
|
+
tag_new_cb_version
|
62
|
+
git_push_commits
|
63
|
+
git_push_tags
|
64
|
+
|
65
|
+
share_new_version
|
66
|
+
|
67
|
+
ui.msg "Version #{@version} of the #{@cb_name} has been released!"
|
68
|
+
ui.msg "Check it out at http://ckbk.it/#{@cb_name}"
|
69
|
+
|
70
|
+
# @TODO: Increment the current version to the next available odd number
|
71
|
+
# algo = n + 1 + (n % 2)
|
72
|
+
if config[:devodd]
|
73
|
+
puts "I'm odd!"
|
74
|
+
end
|
75
|
+
|
76
|
+
end #run
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# Ensure argumanets are valid, assign values of arguments
|
81
|
+
#
|
82
|
+
# @param [Array] the global `name_args` object
|
83
|
+
def validate_args
|
84
|
+
if name_args.size < 1
|
85
|
+
ui.error("No cookbook has been specified")
|
86
|
+
show_usage
|
87
|
+
exit 1
|
88
|
+
end
|
89
|
+
if name_args.size > 2
|
90
|
+
ui.error("Too many arguments are being passed. Please verify.")
|
91
|
+
show_usage
|
92
|
+
exit 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Re-used from Chef
|
97
|
+
def cookbook_loader
|
98
|
+
@cookbook_loader ||= Chef::CookbookLoader.new(config[:cookbook_path])
|
99
|
+
end
|
100
|
+
|
101
|
+
# Validate cookbook existence
|
102
|
+
# Since we can have cookbooks in paths that are not named the same as the directory, using
|
103
|
+
# a metadata entry to describe the cookbook is better. In its absence, uses the directory name.
|
104
|
+
#
|
105
|
+
# @return [String] @cb_path, a string with the root directory of the cookbook
|
106
|
+
# @return [String] @cb_name, a string with the cookbook's name, either from metadata or interpreted from directory
|
107
|
+
def validate_cookbook_exists
|
108
|
+
unless cookbook_loader.cookbook_exists?(@cookbook)
|
109
|
+
ui.error "Cannot find a cookbook named #{@cookbook} at #{config[:cookbook_path]}"
|
110
|
+
exit 2
|
111
|
+
end
|
112
|
+
cb = cookbook_loader.cookbooks_by_name[@cookbook]
|
113
|
+
@cb_path = cb.root_dir
|
114
|
+
@cb_name = cb.metadata.name.to_s
|
115
|
+
@cb_version = Versionomy.parse(cb.version)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Ensure that the cookbook is in a git repo
|
119
|
+
# @TODO: Use Grit instead of shelling out.
|
120
|
+
# Couldn't figure out the rev_parse method invocation on a non-repo.
|
121
|
+
#
|
122
|
+
# @return [String] The absolute file path of the git repository's root
|
123
|
+
# @example
|
124
|
+
# "/Users/miketheman/git/knife-community"
|
125
|
+
def validate_repo
|
126
|
+
begin
|
127
|
+
@repo_root = shellout("git rev-parse --show-toplevel").stdout.chomp
|
128
|
+
rescue Exception => e
|
129
|
+
ui.error "There doesn't seem to be a git repo at #{@cb_path}\n#{e}"
|
130
|
+
exit 3
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Inspect the cookbook directory's git status is good to push.
|
135
|
+
# Any existing tracked files should be staged, otherwise error & exit.
|
136
|
+
# Untracked files are warned about, but will allow continue.
|
137
|
+
# This needs more testing.
|
138
|
+
def validate_repo_clean
|
139
|
+
@gitrepo = Grit::Repo.new(@repo_root)
|
140
|
+
status = @gitrepo.status
|
141
|
+
if !status.changed.nil? or status.changed.size != 0 # This has to be a convoluted way to determine a non-empty...
|
142
|
+
# Test each for the magic sha_index. Ref: https://github.com/mojombo/grit/issues/142
|
143
|
+
status.changed.each do |file|
|
144
|
+
case file[1].sha_index
|
145
|
+
when "0" * 40
|
146
|
+
ui.error "There seem to be unstaged changes in your repo. Either stash or add them."
|
147
|
+
exit 4
|
148
|
+
else
|
149
|
+
ui.msg "There are modified files that have been staged, and will be included in the push."
|
150
|
+
end
|
151
|
+
end
|
152
|
+
elsif status.untracked.size > 0
|
153
|
+
ui.warn "There are untracked files in your repo. You might want to look into that."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Ensure that the version specified is larger than the current version
|
158
|
+
# If a version wasn't specified on the command line, increment the current by one tiny.
|
159
|
+
def validate_version_sanity
|
160
|
+
if @version.nil?
|
161
|
+
@version = @cb_version.bump(:tiny)
|
162
|
+
ui.msg "No version was specified, the new version will be #{@version}"
|
163
|
+
end
|
164
|
+
if @cb_version >= @version
|
165
|
+
ui.error "The current version, #{@cb_version} is either greater or equal to the new version, #{@version}"
|
166
|
+
ui.error "For your own sanity, don't release historical cookbooks into the wild."
|
167
|
+
exit 5
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Ensure that there isn't already a git tag for this version.
|
172
|
+
def validate_no_existing_tag
|
173
|
+
existing_tags = Array.new
|
174
|
+
@gitrepo.tags.each { |tag| existing_tags << tag.name }
|
175
|
+
if existing_tags.include?(@version.to_s)
|
176
|
+
ui.error "This version tag has already been committed to the repo."
|
177
|
+
ui.error "Are you sure you haven't released this already?"
|
178
|
+
exit 6
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Ensure that the remote and branch are indeed valid. We provide defaults in options.
|
183
|
+
def validate_target_remote_branch
|
184
|
+
remote_path = File.join(config[:remote], config[:branch])
|
185
|
+
|
186
|
+
remotes = Array.new
|
187
|
+
@gitrepo.remotes.each { |remote| remotes << remote.name }
|
188
|
+
unless remotes.include?(remote_path)
|
189
|
+
ui.error "The remote/branch specified does not seem to exist."
|
190
|
+
exit 7
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Replace the existing version string with the new version
|
195
|
+
def set_new_cb_version
|
196
|
+
metadata_file = File.join(@cb_path, "metadata.rb")
|
197
|
+
fi = File.read(metadata_file)
|
198
|
+
fi.gsub!(@cb_version.to_s, @version.to_s)
|
199
|
+
fo = File.open(metadata_file, 'w') { |file| file.puts fi }
|
200
|
+
end
|
201
|
+
|
202
|
+
# Using shellout as needed.
|
203
|
+
# @todo Struggled with the Grit::Repo#add for hours.
|
204
|
+
def commit_new_cb_version
|
205
|
+
shellout("git add metadata.rb")
|
206
|
+
@gitrepo.commit_index("release v#{@version}")
|
207
|
+
end
|
208
|
+
|
209
|
+
def tag_new_cb_version
|
210
|
+
shellout("git tag -a -m 'release v#{@version}' #{@version}")
|
211
|
+
end
|
212
|
+
|
213
|
+
# Apparently Grit does not have any `push` semantics yet.
|
214
|
+
def git_push_commits
|
215
|
+
shellout("git push #{config[:remote]} #{config[:branch]}")
|
216
|
+
end
|
217
|
+
|
218
|
+
def git_push_tags
|
219
|
+
shellout("git push #{config[:remote]} --tags")
|
220
|
+
end
|
221
|
+
|
222
|
+
def share_new_version
|
223
|
+
# Need to find the existing cookbook's category. Thankfully, this is readily available via REST/JSON.
|
224
|
+
response = Net::HTTP.get_response("cookbooks.opscode.com", "/api/v1/cookbooks/#{@cb_name}")
|
225
|
+
category = JSON.parse(response.body)['category'] ||= "Other"
|
226
|
+
|
227
|
+
cb_share = Chef::Knife::CookbookSiteShare.new
|
228
|
+
cb_share.name_args = [@cb_name, category]
|
229
|
+
cb_share.run
|
230
|
+
end
|
231
|
+
|
232
|
+
def shellout(command)
|
233
|
+
proc = Mixlib::ShellOut.new(command, :cwd => @cb_path)
|
234
|
+
proc.run_command
|
235
|
+
proc.error!
|
236
|
+
return proc
|
237
|
+
end
|
238
|
+
|
239
|
+
end #class
|
240
|
+
end #module
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-community
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mike Fiedler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: chef
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '10'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '10'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mixlib-shellout
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.1.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.1.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: grit
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: versionomy
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.4'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.4'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0.9'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.9'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.11.0
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.11.0
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: cucumber
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: aruba
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0.4'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0.4'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: tailor
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '1.1'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '1.1'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: travis-lint
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '1.4'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.4'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: guard
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ~>
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '1.3'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ~>
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '1.3'
|
190
|
+
- !ruby/object:Gem::Dependency
|
191
|
+
name: guard-rspec
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
194
|
+
requirements:
|
195
|
+
- - ~>
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '1.2'
|
198
|
+
type: :development
|
199
|
+
prerelease: false
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ~>
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '1.2'
|
206
|
+
- !ruby/object:Gem::Dependency
|
207
|
+
name: guard-cucumber
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
209
|
+
none: false
|
210
|
+
requirements:
|
211
|
+
- - ~>
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '1.2'
|
214
|
+
type: :development
|
215
|
+
prerelease: false
|
216
|
+
version_requirements: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - ~>
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '1.2'
|
222
|
+
description: The centralized location for sharing cookbooks is the Community Site,
|
223
|
+
this is a process helper to produce a repeatable method for releasing cookbooks.
|
224
|
+
email:
|
225
|
+
- miketheman@gmail.com
|
226
|
+
executables: []
|
227
|
+
extensions: []
|
228
|
+
extra_rdoc_files: []
|
229
|
+
files:
|
230
|
+
- .gitignore
|
231
|
+
- .travis.yml
|
232
|
+
- Gemfile
|
233
|
+
- Guardfile
|
234
|
+
- LICENSE
|
235
|
+
- README.md
|
236
|
+
- Rakefile
|
237
|
+
- features/cli.feature
|
238
|
+
- features/support/env.rb
|
239
|
+
- knife-community.gemspec
|
240
|
+
- lib/chef/knife/community_release.rb
|
241
|
+
- lib/knife-community/version.rb
|
242
|
+
- spec/spec_helper.rb
|
243
|
+
homepage: http://miketheman.github.com/knife-community
|
244
|
+
licenses: []
|
245
|
+
post_install_message:
|
246
|
+
rdoc_options: []
|
247
|
+
require_paths:
|
248
|
+
- lib
|
249
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
250
|
+
none: false
|
251
|
+
requirements:
|
252
|
+
- - ! '>='
|
253
|
+
- !ruby/object:Gem::Version
|
254
|
+
version: 1.9.2
|
255
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
256
|
+
none: false
|
257
|
+
requirements:
|
258
|
+
- - ! '>='
|
259
|
+
- !ruby/object:Gem::Version
|
260
|
+
version: '0'
|
261
|
+
segments:
|
262
|
+
- 0
|
263
|
+
hash: -1152703589745345809
|
264
|
+
requirements: []
|
265
|
+
rubyforge_project:
|
266
|
+
rubygems_version: 1.8.24
|
267
|
+
signing_key:
|
268
|
+
specification_version: 3
|
269
|
+
summary: A Knife plugin to assist with deploying completed Chef cookbooks to the Community
|
270
|
+
Site
|
271
|
+
test_files:
|
272
|
+
- features/cli.feature
|
273
|
+
- features/support/env.rb
|
274
|
+
- spec/spec_helper.rb
|