jeweler 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  class Jeweler
2
4
  module Commands
3
5
  class InstallGem
@@ -9,10 +11,22 @@ class Jeweler
9
11
 
10
12
 
11
13
  def run
12
- command = "sudo gem install #{gemspec_helper.gem_path}"
14
+ command = "gem install #{gemspec_helper.gem_path}"
13
15
  output.puts "Executing #{command.inspect}:"
14
16
 
15
- sh command # TODO where does sh actually come from!?
17
+ sh sudo_wrapper(command) # TODO where does sh actually come from!? - rake, apparently
18
+ end
19
+
20
+ def sudo_wrapper(command)
21
+ use_sudo? ? "sudo #{command}" : command
22
+ end
23
+
24
+ def use_sudo?
25
+ host_os !~ /mswin|windows|cygwin/i
26
+ end
27
+
28
+ def host_os
29
+ Config::CONFIG['host_os']
16
30
  end
17
31
 
18
32
  def self.build_for(jeweler)
@@ -12,7 +12,7 @@ class Jeweler
12
12
  end
13
13
 
14
14
  def run
15
- raise "Hey buddy, try committing them files first" if any_pending_changes?
15
+ raise "Hey buddy, try committing them files first" unless clean_staging_area?
16
16
 
17
17
  repo.checkout('master')
18
18
 
@@ -22,11 +22,12 @@ class Jeweler
22
22
  output.puts "Pushing master to origin"
23
23
  repo.push
24
24
 
25
- tag_release! unless release_tagged?
25
+ tag_release! if release_not_tagged?
26
26
  end
27
27
 
28
- def any_pending_changes?
29
- !(@repo.status.added.empty? && @repo.status.deleted.empty? && @repo.status.changed.empty?)
28
+ def clean_staging_area?
29
+ status = repo.status
30
+ status.added.empty? && status.deleted.empty? && status.changed.empty?
30
31
  end
31
32
 
32
33
  def tag_release!
@@ -52,13 +53,15 @@ class Jeweler
52
53
  "v#{version}"
53
54
  end
54
55
 
55
- def release_tagged?
56
+ def release_not_tagged?
56
57
  tag = repo.tag(release_tag) rescue nil
57
- ! tag.nil?
58
+ tag.nil?
58
59
  end
59
60
 
60
61
  def gemspec_changed?
61
- any_pending_changes?
62
+ `git status` # OMGHAX. status always ends up being 'M' unless this runs
63
+ status = repo.status[gemspec_helper.path]
64
+ ! status.type.nil?
62
65
  end
63
66
 
64
67
  def gemspec_helper
@@ -11,7 +11,26 @@ class Jeweler
11
11
  output.puts "Logging into rubyforge"
12
12
  @rubyforge.login
13
13
 
14
+ if package_exists?
15
+ output.puts "#{@gemspec.name} package already exists in the #{@gemspec.rubyforge_project} project"
16
+ return
17
+ end
18
+
14
19
  output.puts "Creating #{@gemspec.name} package in the #{@gemspec.rubyforge_project} project"
20
+ create_package
21
+ end
22
+
23
+ def package_exists?
24
+ begin
25
+ @rubyforge.lookup 'package', @gemspec.name
26
+ true
27
+ rescue RuntimeError => e
28
+ raise unless e.message == "no <package_id> configured for <#{@gemspec.name}>"
29
+ false
30
+ end
31
+ end
32
+
33
+ def create_package
15
34
  begin
16
35
  @rubyforge.create_package(@gemspec.rubyforge_project, @gemspec.name)
17
36
  rescue StandardError => e
@@ -30,6 +30,9 @@ class Jeweler
30
30
  gemspec_ruby = prettyify_array(gemspec_ruby, :files)
31
31
  gemspec_ruby = prettyify_array(gemspec_ruby, :test_files)
32
32
  gemspec_ruby = prettyify_array(gemspec_ruby, :extra_rdoc_files)
33
+ f.puts "# Generated by jeweler"
34
+ f.puts "# DO NOT EDIT THIS FILE"
35
+ f.puts "# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`"
33
36
  f.write gemspec_ruby
34
37
  end
35
38
  end
@@ -28,13 +28,16 @@ class Jeweler
28
28
  end
29
29
 
30
30
  class Generator
31
- attr_accessor :target_dir, :user_name, :user_email, :summary, :testing_framework,
31
+ attr_accessor :target_dir, :user_name, :user_email, :summary,
32
32
  :project_name, :github_username, :github_token,
33
- :repo, :should_create_repo, :should_use_cucumber, :should_setup_rubyforge,
33
+ :repo, :should_create_repo,
34
+ :testing_framework, :documentation_framework,
35
+ :should_use_cucumber, :should_setup_rubyforge,
34
36
  :should_use_reek, :should_use_roodi,
35
37
  :description
36
38
 
37
39
  DEFAULT_TESTING_FRAMEWORK = :shoulda
40
+ DEFAULT_DOCUMENTATION_FRAMEWORK = :rdoc
38
41
 
39
42
  def initialize(project_name, options = {})
40
43
  if project_name.nil? || project_name.squeeze.strip == ""
@@ -44,6 +47,7 @@ class Jeweler
44
47
  self.project_name = project_name
45
48
 
46
49
  self.testing_framework = (options[:testing_framework] || DEFAULT_TESTING_FRAMEWORK).to_sym
50
+ self.documentation_framework = options[:documentation_framework] || DEFAULT_DOCUMENTATION_FRAMEWORK
47
51
  begin
48
52
  generator_mixin_name = "#{self.testing_framework.to_s.capitalize}Mixin"
49
53
  generator_mixin = self.class.const_get(generator_mixin_name)
@@ -127,14 +131,19 @@ class Jeweler
127
131
  File.join(features_dir, 'step_definitions')
128
132
  end
129
133
 
134
+ def doc_task
135
+ case documentation_framework
136
+ when :yard then "yardoc"
137
+ else
138
+ documentation_framework.to_s
139
+ end
140
+ end
141
+
130
142
  protected
131
143
 
132
144
  # This is in a separate method so we can stub it out during testing
133
145
  def read_git_config
134
- # we could just use Git::Base's .config, but that relies on a repo being around already
135
- # ... which we don't have yet, since this is part of a sanity check
136
- lib = Git::Lib.new(nil, nil)
137
- config = lib.parse_config '~/.gitconfig'
146
+ Git.global_config
138
147
  end
139
148
 
140
149
  private
@@ -7,7 +7,8 @@ class Jeweler
7
7
  super()
8
8
 
9
9
  @orig_args = args.clone
10
- self[:testing_framework] = :shoulda
10
+ self[:testing_framework] = :shoulda
11
+ self[:documentation_framework] = :rdoc
11
12
 
12
13
  @opts = OptionParser.new do |o|
13
14
  o.banner = "Usage: #{File.basename($0)} [options] reponame\ne.g. #{File.basename($0)} the-perfect-gem"
@@ -68,6 +69,14 @@ class Jeweler
68
69
  self[:directory] = directory
69
70
  end
70
71
 
72
+ o.on('--yard', 'use yard for documentation') do
73
+ self[:documentation_framework] = :yard
74
+ end
75
+
76
+ o.on('--rdoc', 'use rdoc for documentation') do
77
+ self[:documentation_framework] = :rdoc
78
+ end
79
+
71
80
  o.on_tail('-h', '--help', 'display this help and exit') do
72
81
  self[:show_help] = true
73
82
  end
@@ -4,8 +4,29 @@ require 'rake/contrib/sshpublisher'
4
4
 
5
5
 
6
6
  class Jeweler
7
+ # Rake tasks for putting a Jeweler gem on Rubyforge.
8
+ #
9
+ # Jeweler::Tasks.new needs to be used before this.
10
+ #
11
+ # Basic usage:
12
+ #
13
+ # Jeweler::RubyforgeTasks.new
14
+ #
15
+ # Easy enough, right?
16
+ #
17
+ # There are a few options you can tweak:
18
+ #
19
+ # * project: the rubyforge project to operate on. This defaults to whatever you specified in your gemspec. Defaults to your gem name.
20
+ # * remote_doc_path: the place to upload docs to on Rubyforge under /var/www/gforge-projects/#{project}/
21
+ #
7
22
  class RubyforgeTasks < ::Rake::TaskLib
8
- attr_accessor :project, :remote_doc_path
23
+ # The RubyForge project to interact with. Defaults to whatever is in your jeweler gemspec.
24
+ attr_accessor :project
25
+ # The path to upload docs to. It is relative to /var/www/gforge-projects/#{project}/, and defaults to your gemspec's name
26
+ attr_accessor :remote_doc_path
27
+ # Task to be used for generating documentation, before they are uploaded. Defaults to rdoc.
28
+ attr_accessor :doc_task
29
+
9
30
  attr_accessor :jeweler
10
31
 
11
32
  def initialize
@@ -15,6 +36,7 @@ class Jeweler
15
36
 
16
37
  self.remote_doc_path ||= jeweler.gemspec.name
17
38
  self.project ||= jeweler.gemspec.rubyforge_project
39
+ self.doc_task ||= :rdoc
18
40
 
19
41
  define
20
42
  end
@@ -26,21 +48,51 @@ class Jeweler
26
48
  task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
27
49
 
28
50
  namespace :release do
29
- desc "Publish RDoc to RubyForge."
30
- task :docs => [:rdoc] do
51
+ desc "Release the current gem version to RubyForge."
52
+ task :gem => [:gemspec, :build] do
53
+ begin
54
+ jeweler.release_gem_to_rubyforge
55
+ rescue NoRubyForgeProjectInGemspecError => e
56
+ abort "Setting up RubyForge requires that you specify a 'rubyforge_project' in your Jeweler::Tasks declaration"
57
+ rescue MissingRubyForgePackageError => e
58
+ abort "Rubyforge reported that the #{e.message} package isn't setup. Run rake rubyforge:setup to do so."
59
+ rescue RubyForgeProjectNotConfiguredError => e
60
+ abort "RubyForge reported that #{e.message} wasn't configured. This means you need to run 'rubyforge setup', 'rubyforge login', and 'rubyforge configure', or maybe the project doesn't exist on RubyForge"
61
+ end
62
+ end
63
+
64
+ desc "Publish docs to RubyForge."
65
+ task :docs => doc_task do
31
66
  config = YAML.load(
32
67
  File.read(File.expand_path('~/.rubyforge/user-config.yml'))
33
68
  )
34
69
 
35
70
  host = "#{config['username']}@rubyforge.org"
36
71
  remote_dir = "/var/www/gforge-projects/#{project}/#{remote_doc_path}"
37
- local_dir = 'rdoc'
72
+
73
+ local_dir = case self.doc_task.to_sym
74
+ when :rdoc then 'rdoc'
75
+ when :yardoc then 'doc'
76
+ else
77
+ raise "Unsure what to run to generate documentation. Please set doc_task and re-run."
78
+ end
38
79
 
39
80
  sh %{rsync -av --delete #{local_dir}/ #{host}:#{remote_dir}}
40
81
  end
41
82
  end
83
+
84
+ desc "Setup a rubyforge project for this gem"
85
+ task :setup do
86
+ begin
87
+ jeweler.setup_rubyforge
88
+ rescue NoRubyForgeProjectInGemspecError => e
89
+ abort "Setting up RubyForge requires that you specify a 'rubyforge_project' in your Jeweler::Tasks declaration"
90
+ rescue RubyForgeProjectNotConfiguredError => e
91
+ abort "The RubyForge reported that #{e.message} wasn't configured. This means you need to run 'rubyforge setup', 'rubyforge login', and 'rubyforge configure', or maybe the project doesn't exist on RubyForge"
92
+ end
93
+ end
94
+
42
95
  end
43
-
44
96
  end
45
97
  end
46
98
  end
@@ -31,12 +31,12 @@ class Jeweler
31
31
  self.files = repo.ls_files.keys - repo.lib.ignored_files
32
32
  end
33
33
 
34
- if blank?(test_files)
34
+ if blank?(test_files) && File.directory?(File.join(base_dir, '.git'))
35
35
  repo = Git.open(base_dir)
36
36
  self.test_files = FileList['{spec,test,examples}/**/*.rb'] - repo.lib.ignored_files
37
37
  end
38
38
 
39
- if blank?(executable)
39
+ if blank?(executables)
40
40
  self.executables = Dir["bin/*"].map { |f| File.basename(f) }
41
41
  end
42
42
 
data/lib/jeweler/tasks.rb CHANGED
@@ -6,6 +6,28 @@ class Rake::Application
6
6
  end
7
7
 
8
8
  class Jeweler
9
+ # Rake tasks for managing your gem.
10
+ #
11
+ # Here's a basic example of using it:
12
+ #
13
+ # Jeweler::Tasks.new do |gem|
14
+ # gem.name = "jeweler"
15
+ # gem.summary = "Simple and opinionated helper for creating Rubygem projects on GitHub"
16
+ # gem.email = "josh@technicalpickles.com"
17
+ # gem.homepage = "http://github.com/technicalpickles/jeweler"
18
+ # gem.description = "Simple and opinionated helper for creating Rubygem projects on GitHub"
19
+ # gem.authors = ["Josh Nichols"]
20
+ # end
21
+ #
22
+ # The block variable gem is actually a Gem::Specification, so you can do anything you would normally do with a Gem::Specification. For more details, see the official gemspec reference: http://docs.rubygems.org/read/chapter/20
23
+ #
24
+ # Jeweler fills in a few reasonable defaults for you:
25
+ #
26
+ # [gem.files] a Rake::FileList of anything that is in git and not gitignored. You can include/exclude this default set, or override it entirely
27
+ # [gem.test_files] Similar to gem.files, except it's only things under the spec, test, or examples directory.
28
+ # [gem.extra_rdoc_files] a Rake::FileList including files like README*, ChangeLog*, and LICENSE*
29
+ # [gem.executables] uses anything found in the bin/ directory. You can override this.
30
+ #
9
31
  class Tasks < ::Rake::TaskLib
10
32
  attr_accessor :gemspec, :jeweler
11
33
 
@@ -90,34 +112,6 @@ class Jeweler
90
112
  jeweler.release
91
113
  end
92
114
 
93
- namespace :rubyforge do
94
- namespace :release do
95
- desc "Release the current gem version to RubyForge."
96
- task :gem => [:gemspec, :build] do
97
- begin
98
- jeweler.release_gem_to_rubyforge
99
- rescue NoRubyForgeProjectInGemspecError => e
100
- abort "Setting up RubyForge requires that you specify a 'rubyforge_project' in your Jeweler::Tasks declaration"
101
- rescue MissingRubyForgePackageError => e
102
- abort "Rubyforge reported that the #{e.message} package isn't setup. Run rake rubyforge:setup to do so."
103
- rescue RubyForgeProjectNotConfiguredError => e
104
- abort "RubyForge reported that #{e.message} wasn't configured. This means you need to run 'rubyforge setup', 'rubyforge login', and 'rubyforge configure', or maybe the project doesn't exist on RubyForge"
105
- end
106
- end
107
- end
108
-
109
- desc "Setup a rubyforge project for this gem"
110
- task :setup do
111
- begin
112
- jeweler.setup_rubyforge
113
- rescue NoRubyForgeProjectInGemspecError => e
114
- abort "Setting up RubyForge requires that you specify a 'rubyforge_project' in your Jeweler::Tasks declaration"
115
- rescue RubyForgeProjectNotConfiguredError => e
116
- abort "The RubyForge reported that #{e.message} wasn't configured. This means you need to run 'rubyforge setup', 'rubyforge login', and 'rubyforge configure', or maybe the project doesn't exist on RubyForge"
117
- end
118
- end
119
-
120
- end
121
115
  end
122
116
  end
123
117
  end
@@ -17,7 +17,9 @@ begin
17
17
  end
18
18
 
19
19
  <% if should_setup_rubyforge %>
20
- Jeweler::RubyforgeTasks.new
20
+ Jeweler::RubyforgeTasks.new do |rubyforge|
21
+ rubyforge.doc_task = "<%= doc_task %>"
22
+ end
21
23
  <% end %>
22
24
  rescue LoadError
23
25
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
@@ -115,11 +117,12 @@ end
115
117
 
116
118
  task :default => :<%= default_task %>
117
119
 
120
+ <% case documentation_framework %>
121
+ <% when :rdoc %>
118
122
  require 'rake/rdoctask'
119
123
  Rake::RDocTask.new do |rdoc|
120
- if File.exist?('VERSION.yml')
121
- config = YAML.load(File.read('VERSION.yml'))
122
- version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
124
+ if File.exist?('VERSION')
125
+ version = File.read('VERSION')
123
126
  else
124
127
  version = ""
125
128
  end
@@ -129,4 +132,13 @@ Rake::RDocTask.new do |rdoc|
129
132
  rdoc.rdoc_files.include('README*')
130
133
  rdoc.rdoc_files.include('lib/**/*.rb')
131
134
  end
132
-
135
+ <% when :yard %>
136
+ begin
137
+ require 'yard'
138
+ YARD::Rake::YardocTask.new
139
+ rescue LoadError
140
+ task :yardoc do
141
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
142
+ end
143
+ end
144
+ <% end %>
@@ -3,6 +3,59 @@ require 'test_helper'
3
3
  class Jeweler
4
4
  module Commands
5
5
  class TestInstallGem < Test::Unit::TestCase
6
+ rubyforge_command_context "running" do
7
+ setup do
8
+ stub(@gemspec_helper).gem_path { 'pkg/zomg-1.1.1.gem' }
9
+ stub(@command).sudo_wrapper { 'sudo gem install pkg/zomg-1.1.1.gem' }
10
+ stub(@command).sh
11
+
12
+ @command.run
13
+ end
14
+
15
+ should "call sudo wrapper with gem install" do
16
+ assert_received(@command) {|command| command.sudo_wrapper('gem install pkg/zomg-1.1.1.gem') }
17
+ end
18
+
19
+ should "call sh with output of sudo wrapper" do
20
+ assert_received(@command) {|command| command.sh 'sudo gem install pkg/zomg-1.1.1.gem' }
21
+ end
22
+ end
23
+
24
+ rubyforge_command_context "use_sudo?" do
25
+ should "be false on mswin" do
26
+ stub(@command).host_os { "i386-mswin32" }
27
+ assert ! @command.use_sudo?
28
+ end
29
+
30
+ should "be false on windows" do
31
+ stub(@command).host_os { "windows" }
32
+ assert ! @command.use_sudo?
33
+ end
34
+
35
+ should "be false on cygwin" do
36
+ stub(@command).host_os { "cygwin" }
37
+ assert ! @command.use_sudo?
38
+ end
39
+
40
+ should "be true on basically anything else" do
41
+ stub(@command).host_os { "darwin9" }
42
+ assert @command.use_sudo?
43
+ end
44
+ end
45
+
46
+ rubyforge_command_context "sudo_wrapper" do
47
+ should "prefix sudo if needed" do
48
+ stub(@command).use_sudo? { true }
49
+ assert_equal "sudo blarg", @command.sudo_wrapper("blarg")
50
+ end
51
+
52
+ should "not prefix with sudo if unneeded" do
53
+ stub(@command).use_sudo? { false }
54
+ assert_equal "blarg", @command.sudo_wrapper("blarg")
55
+ end
56
+ end
57
+
58
+
6
59
  build_command_context "build for jeweler" do
7
60
  setup do
8
61
  @command = Jeweler::Commands::InstallGem.build_for(@jeweler)