rubygems-tasks - initial gem2deb package.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Sun, 23 Mar 2014 21:52:57 +0000 (22:52 +0100)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Sun, 23 Mar 2014 21:52:57 +0000 (22:52 +0100)
53 files changed:
ruby-rubygems-tasks/.document [new file with mode: 0644]
ruby-rubygems-tasks/.gitignore [new file with mode: 0644]
ruby-rubygems-tasks/.rspec [new file with mode: 0644]
ruby-rubygems-tasks/.yardopts [new file with mode: 0644]
ruby-rubygems-tasks/ChangeLog.md [new file with mode: 0644]
ruby-rubygems-tasks/LICENSE.txt [new file with mode: 0644]
ruby-rubygems-tasks/README.md [new file with mode: 0644]
ruby-rubygems-tasks/Rakefile [new file with mode: 0644]
ruby-rubygems-tasks/debian/changelog [new file with mode: 0644]
ruby-rubygems-tasks/debian/compat [new file with mode: 0644]
ruby-rubygems-tasks/debian/control [new file with mode: 0644]
ruby-rubygems-tasks/debian/copyright [new file with mode: 0644]
ruby-rubygems-tasks/debian/ruby-rubygems-tasks.docs [new file with mode: 0644]
ruby-rubygems-tasks/debian/ruby-test-files.yaml [new file with mode: 0644]
ruby-rubygems-tasks/debian/rules [new file with mode: 0755]
ruby-rubygems-tasks/debian/source/format [new file with mode: 0644]
ruby-rubygems-tasks/debian/watch [new file with mode: 0644]
ruby-rubygems-tasks/gemspec.yml [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/build.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/build/gem.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/build/tar.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/build/task.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/build/zip.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/console.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/install.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/printing.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/project.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/push.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/release.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/scm.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/scm/push.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/scm/status.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/scm/tag.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/sign.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/sign/checksum.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/sign/pgp.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/sign/task.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/task.rb [new file with mode: 0644]
ruby-rubygems-tasks/lib/rubygems/tasks/tasks.rb [new file with mode: 0644]
ruby-rubygems-tasks/metadata.yml [new file with mode: 0644]
ruby-rubygems-tasks/rubygems-tasks.gemspec [new file with mode: 0644]
ruby-rubygems-tasks/spec/console_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/install_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/project_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/push_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/rake_context.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/scm/push_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/scm/status_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/scm/tag_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/sign/pgp_spec.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/spec_helper.rb [new file with mode: 0644]
ruby-rubygems-tasks/spec/tasks_spec.rb [new file with mode: 0644]

diff --git a/ruby-rubygems-tasks/.document b/ruby-rubygems-tasks/.document
new file mode 100644 (file)
index 0000000..bf7d6f2
--- /dev/null
@@ -0,0 +1,5 @@
+lib/**/*.rb
+bin/*
+- 
+ChangeLog.*
+LICENSE.txt
diff --git a/ruby-rubygems-tasks/.gitignore b/ruby-rubygems-tasks/.gitignore
new file mode 100644 (file)
index 0000000..4603547
--- /dev/null
@@ -0,0 +1,3 @@
+doc/
+pkg/
+data/projects/
diff --git a/ruby-rubygems-tasks/.rspec b/ruby-rubygems-tasks/.rspec
new file mode 100644 (file)
index 0000000..660778b
--- /dev/null
@@ -0,0 +1 @@
+--colour --format documentation
diff --git a/ruby-rubygems-tasks/.yardopts b/ruby-rubygems-tasks/.yardopts
new file mode 100644 (file)
index 0000000..1e589cd
--- /dev/null
@@ -0,0 +1 @@
+--markup markdown --title "Gem::Tasks Documentation" --protected
diff --git a/ruby-rubygems-tasks/ChangeLog.md b/ruby-rubygems-tasks/ChangeLog.md
new file mode 100644 (file)
index 0000000..df865d5
--- /dev/null
@@ -0,0 +1,115 @@
+### 0.2.4 / 2013-04-8
+
+* Use the new `Gem::Package` class when running under Ruby 2.0.0.
+* Fix `hg showconfig extensions hgext gpg` empty test by ignoring the trailing
+  new-line (thanks @wrzasa).
+
+### 0.2.3 / 2012-04-30
+
+* {Gem::Tasks::Printing#status} and {Gem::Tasks::Printing#debug} will not
+  produce output if `Rake.verbose` is false.
+* Added specs for {Gem::Tasks::Sign::PGP}.
+
+#### sign:pgp
+
+* Generate detached PGP signatures using `--detach-sign`.
+
+### 0.2.2 / 2012-04-29
+
+* Added {Gem::Tasks::Task#invoke}.
+
+#### build:*
+
+* Explicitly invoke the `validate` task from within package file tasks.
+  This prevents package file tasks from always being triggered, due to the
+  dependency on `validate`.
+
+### 0.2.1 / 2012-04-29
+
+* Overrode the `FileUtils.fu_output_message` to call
+  {Gem::Tasks::Printing#debug}.
+* Added `@api semipublic` tags to mark the semi-public API.
+* Fixed a spelling error.
+
+#### console
+
+* Infer the primary file to require from the gemspec name.
+* No longer run `bundle console`, since it is not the same as running
+  `bundle exec irb -Ilib -rfoo/bar`.
+
+#### scm:status
+
+* Will display the human-readable status, if the repository is dirty.
+* Hooks into the `validate` task.
+
+#### scm:push
+
+* Depends on the `validate` task.
+
+#### scm:tag
+
+* Depends on the `validate` task.
+
+#### build:*
+
+* All `build:*` tasks now depend on the `validate` task.
+
+#### push
+
+* Depends on the `validate` task.
+
+### 0.2.0 / 2012-04-27
+
+* Removed `Gem::Tasks::Task.task_name`.
+
+#### scm:status
+
+* Now ignores untracked files.
+* Will prevent any packages from being built, if the repository is dirty.
+
+#### scm:tag
+
+* Now create `v` prefixed version tags by default.
+* Now supports creating PGP signed Git/Mercurial tags.
+* {Gem::Tasks::SCM::Tag#initialize} now accepts the `:sign` option,
+  for enabling/disabling tag signing on a per-project basis.
+* Added {Gem::Tasks::SCM::Tag#sign?} and {Gem::Tasks::SCM::Tag#sign=}.
+
+### 0.1.2 / 2012-04-26
+
+#### scm:push
+
+* Now runs `git push` then `git push --tags`.
+
+### 0.1.1 / 2012-04-26
+
+#### console
+
+* require `rubygems` on Ruby 1.8.
+* require the first `lib/` file to load the project.
+
+#### sign:pgp
+
+* Now creates ASCII armored signatures.
+
+### 0.1.0 / 2012-04-24
+
+* Initial release:
+  * Added {Gem::Tasks::Project}.
+  * Added {Gem::Tasks::Printing}.
+  * Added {Gem::Tasks::Task}.
+  * Added {Gem::Tasks::Build::Task}.
+  * Added {Gem::Tasks::Build::Gem}.
+  * Added {Gem::Tasks::Build::Tar}.
+  * Added {Gem::Tasks::Build::Zip}.
+  * Added {Gem::Tasks::SCM::Push}.
+  * Added {Gem::Tasks::SCM::Status}.
+  * Added {Gem::Tasks::SCM::Tag}.
+  * Added {Gem::Tasks::Sign::Task}.
+  * Added {Gem::Tasks::Sign::Checksum}.
+  * Added {Gem::Tasks::Sign::PGP}.
+  * Added {Gem::Tasks::Console}.
+  * Added {Gem::Tasks::Install}.
+  * Added {Gem::Tasks::Push}.
+  * Added {Gem::Tasks::Release}.
+  * Added {Gem::Tasks}.
diff --git a/ruby-rubygems-tasks/LICENSE.txt b/ruby-rubygems-tasks/LICENSE.txt
new file mode 100644 (file)
index 0000000..9988fd3
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright (c) 2011-2013 Hal Brodigan
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/ruby-rubygems-tasks/README.md b/ruby-rubygems-tasks/README.md
new file mode 100644 (file)
index 0000000..dd0b1e2
--- /dev/null
@@ -0,0 +1,117 @@
+# rubygems-tasks
+
+* [Source](https://github.com/postmodern/rubygems-tasks)
+* [Issues](https://github.com/postmodern/rubygems-tasks/issues)
+* [Email](mailto:postmodern.mod3 at gmail.com)
+
+## Description
+
+rubygems-tasks provides agnostic and unobtrusive Rake tasks for building,
+installing and releasing Ruby Gems.
+
+    require 'rubygems/tasks'
+    Gem::Tasks.new
+
+## Philosophy
+
+The Rake tasks which you use to manage a Ruby project should not be coupled
+to the project generator which you used to create the project.
+Project generators have nothing to do with the Rake tasks used to build,
+install and release a Ruby project.
+
+Recently, many Ruby Developers began creating Ruby projects by hand,
+building/releasing RubyGems using `gem build` / `gem push`. Sometimes this
+resulted in RubyGems being released with uncommitted changes, or the developer
+forgetting to tag the release. Ruby Developers should have access to
+**agnostic** and **unobtrusive** Rake tasks, to **automate** the release
+process.
+
+This is what rubygems-tasks seeks to provide.
+
+## Features
+
+* Provides tasks to build, install and push gems to [rubygems.org].
+  * Loads all project metadata from the `.gemspec` file.
+  * Supports loading multiple `.gemspec` files.
+  * Supports pushing gems to alternate [Gemcutter] servers.
+* Supports optionally building `.tar.gz` and `.zip` archives.
+  * `build:tar`
+  * `build:zip`
+* Supports [Git], [Mercurial] and [SubVersion] Source-Code-Managers
+  (SCMs).
+  * Supports creating PGP signed Git/Mercurial tags.
+* Provides optional `sign` tasks for package integrity:
+  * `sign:checksum`
+  * `sign:pgp`
+* Provides a `console` task, for jumping right into your code.
+* Defines task aliases for users coming from [Jeweler] or [Hoe].
+* ANSI coloured messages!
+
+## Anti-Features
+
+* **Does not** parse project metadata from the README or the ChangeLog.
+* **Does not** generate or modify code.
+* **Does not** automatically commit changes.
+* **Does not** inject dependencies into gems.
+* **Zero** dependencies.
+
+## Install
+
+    $ gem install rubygems-tasks
+
+## Examples
+
+Specifying an alternate Ruby Console to run:
+
+    Gem::Tasks.new do |tasks|
+      tasks.console.command = 'pry'
+    end
+
+Enable pushing gems to an in-house [Gemcutter] server:
+
+    Gem::Tasks.new do |tasks|
+      tasks.push.host = 'gems.company.com'
+    end
+
+Disable the `push` task:
+
+    Gem::Tasks.new(:push => false)
+
+Enable building `.tar.gz` and `.zip` archives:
+
+    Gem::Tasks.new(:build => {:tar => true, :zip => true})
+
+Enable Checksums and PGP signatures for built packages:
+
+    Gem::Tasks.new(:sign => {:checksum => true, :pgp => true})
+
+Selectively defining tasks:
+
+    Gem::Build::Tar.new
+    Gem::SCM::Status.new
+    Gem::SCM::Tag.new(:format => 'REL-%s')
+    Gem::Sign::Checksum.new
+    Gem::Console.new
+
+## Synopsis
+
+    rake build    # Builds all packages
+    rake console  # Spawns an Interactive Ruby Console
+    rake install  # Installs all built gem packages
+    rake release  # Performs a release
+
+## Copyright
+
+Copyright (c) 2011-2013 Hal Brodigan
+
+See {file:LICENSE.txt} for details.
+
+[Git]: http://git-scm.com/
+[Mercurial]: http://mercurial.selenic.com/
+[SubVersion]: http://subversion.tigris.org/
+
+[Jeweler]: https://github.com/technicalpickles/jeweler#readme
+[Hoe]: https://github.com/seattlerb/hoe#readme
+
+[rubygems.org]: https://rubygems.org/
+[Gemcutter]: https://github.com/rubygems/rubygems.org#readme
diff --git a/ruby-rubygems-tasks/Rakefile b/ruby-rubygems-tasks/Rakefile
new file mode 100644 (file)
index 0000000..0edb5e3
--- /dev/null
@@ -0,0 +1,79 @@
+require 'rubygems'
+require 'rake'
+
+lib_dir = File.expand_path('lib',File.dirname(__FILE__))
+$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
+
+require 'rubygems/tasks'
+Gem::Tasks.new(
+  :build => {:gem => true, :tar => true},
+  :sign  => {:checksum => true, :pgp => true}
+)
+
+begin
+  gem 'rspec', '~> 2.4'
+  require 'rspec/core/rake_task'
+  
+  RSpec::Core::RakeTask.new
+rescue LoadError
+  task :spec do
+    abort "Please run `gem install rspec` to install RSpec."
+  end
+end
+task :test => :spec
+task :default => :spec
+
+begin
+  gem 'yard', '~> 0.7'
+  require 'yard'
+
+  YARD::Rake::YardocTask.new  
+rescue LoadError => e
+  task :yard do
+    abort 'Please run `gem install yard` to install YARD.'
+  end
+end
+
+require 'net/https'
+require 'uri'
+
+DOWNLOAD_URI = 'http://cloud.github.com/downloads/postmodern/rubygems-tasks/'
+PROJECTS_DIR = File.join('data','projects')
+PROJECTS     = %w[rubygems-project rubygems-multi-project bundler-project]
+
+directory PROJECTS_DIR
+
+PROJECTS.each do |project|
+  project_file = "#{project}.tar.gz"
+  project_path = File.join(PROJECTS_DIR,project_file)
+  project_dir  = File.join(PROJECTS_DIR,project)
+
+  file project_path => PROJECTS_DIR do
+    Net::HTTP.get_response(URI(DOWNLOAD_URI + project_file)) do |response|
+      size, total = 0, response.header['Content-Length'].to_i
+
+      puts ">>> Downloading to #{project_file} to #{project_path} ..."
+
+      File.open(project_path,"wb") do |file|
+        response.read_body do |chunk|
+          file.write(chunk)
+
+          size += chunk.size
+          printf "\r>>> [%d / %d] %d%% ...", size, total, ((size * 100) / total)
+        end
+      end
+
+      puts
+    end
+  end
+
+  task project_dir => project_path do
+    unless File.directory?(project_dir)
+      sh 'tar', 'xzf', project_path, '-C', PROJECTS_DIR
+    end
+  end
+
+  task 'data:projects' => project_dir
+end
+
+task :spec => 'data:projects'
diff --git a/ruby-rubygems-tasks/debian/changelog b/ruby-rubygems-tasks/debian/changelog
new file mode 100644 (file)
index 0000000..89596a4
--- /dev/null
@@ -0,0 +1,5 @@
+ruby-rubygems-tasks (0.2.4-1) UNRELEASED; urgency=medium
+
+  * Initial release (Closes: #nnnn)
+
+ -- František Dvořák <valtri@civ.zcu.cz>  Sun, 23 Mar 2014 22:50:41 +0100
diff --git a/ruby-rubygems-tasks/debian/compat b/ruby-rubygems-tasks/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/ruby-rubygems-tasks/debian/control b/ruby-rubygems-tasks/debian/control
new file mode 100644 (file)
index 0000000..5933b8e
--- /dev/null
@@ -0,0 +1,19 @@
+Source: ruby-rubygems-tasks
+Section: ruby
+Priority: optional
+Maintainer: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers@lists.alioth.debian.org>
+Uploaders: František Dvořák <valtri@civ.zcu.cz>
+Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.6.1~)
+Standards-Version: 3.9.4
+#Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-rubygems-tasks.git
+#Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-ruby-extras/ruby-rubygems-tasks.git;a=summary
+Homepage: https://github.com/postmodern/rubygems-tasks#readme
+XS-Ruby-Versions: all
+
+Package: ruby-rubygems-tasks
+Architecture: all
+XB-Ruby-Versions: ${ruby:Versions}
+Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter
+# rspec (~> 2.4, development), yard (~> 0.7, development)
+Description: Rake tasks for managing and releasing Ruby Gems.
+ Agnostic and unobtrusive Rake tasks for managing and releasing Ruby Gems.
diff --git a/ruby-rubygems-tasks/debian/copyright b/ruby-rubygems-tasks/debian/copyright
new file mode 100644 (file)
index 0000000..c2e9b7d
--- /dev/null
@@ -0,0 +1,35 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: rubygems-tasks
+Source: FIXME <http://example.com/>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+           <years> <likewise for another author>
+License: GPL-2+ (FIXME)
+
+Files: debian/*
+Copyright: 2014 František Dvořák <valtri@civ.zcu.cz>
+License: GPL-2+ (FIXME)
+Comment: the Debian packaging is licensed under the same terms as the original package.
+
+License: GPL-2+ (FIXME)
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ .
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the GNU General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
diff --git a/ruby-rubygems-tasks/debian/ruby-rubygems-tasks.docs b/ruby-rubygems-tasks/debian/ruby-rubygems-tasks.docs
new file mode 100644 (file)
index 0000000..07b3c9e
--- /dev/null
@@ -0,0 +1,2 @@
+# FIXME: READMEs found
+# README.md
diff --git a/ruby-rubygems-tasks/debian/ruby-test-files.yaml b/ruby-rubygems-tasks/debian/ruby-test-files.yaml
new file mode 100644 (file)
index 0000000..8de9577
--- /dev/null
@@ -0,0 +1,10 @@
+---
+- spec/console_spec.rb
+- spec/install_spec.rb
+- spec/project_spec.rb
+- spec/push_spec.rb
+- spec/scm/push_spec.rb
+- spec/scm/status_spec.rb
+- spec/scm/tag_spec.rb
+- spec/sign/pgp_spec.rb
+- spec/tasks_spec.rb
diff --git a/ruby-rubygems-tasks/debian/rules b/ruby-rubygems-tasks/debian/rules
new file mode 100755 (executable)
index 0000000..82ddc0c
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+#export DH_VERBOSE=1
+#
+# Uncomment to ignore all test failures (but the tests will run anyway)
+#export DH_RUBY_IGNORE_TESTS=all
+#
+# Uncomment to ignore some test failures (but the tests will run anyway).
+# Valid values:
+#export DH_RUBY_IGNORE_TESTS=ruby1.9.1 ruby2.0 require-rubygems
+#
+# If you need to specify the .gemspec (eg there is more than one)
+#export DH_RUBY_GEMSPEC=gem.gemspec
+
+%:
+       dh $@ --buildsystem=ruby --with ruby
diff --git a/ruby-rubygems-tasks/debian/source/format b/ruby-rubygems-tasks/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/ruby-rubygems-tasks/debian/watch b/ruby-rubygems-tasks/debian/watch
new file mode 100644 (file)
index 0000000..61d78d7
--- /dev/null
@@ -0,0 +1,2 @@
+version=3
+http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/rubygems-tasks .*/rubygems-tasks-(.*).tar.gz
diff --git a/ruby-rubygems-tasks/gemspec.yml b/ruby-rubygems-tasks/gemspec.yml
new file mode 100644 (file)
index 0000000..7cb9b18
--- /dev/null
@@ -0,0 +1,14 @@
+name: rubygems-tasks
+version: 0.2.4
+summary: Rake tasks for managing and releasing Ruby Gems.
+description:
+  Agnostic and unobtrusive Rake tasks for managing and releasing Ruby Gems.
+
+authors: Postmodern
+email: postmodern.mod3@gmail.com
+homepage: https://github.com/postmodern/rubygems-tasks#readme
+has_yard: true
+
+development_dependencies:
+  rspec: ~> 2.4
+  yard: ~> 0.7
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks.rb b/ruby-rubygems-tasks/lib/rubygems/tasks.rb
new file mode 100644 (file)
index 0000000..29e5a82
--- /dev/null
@@ -0,0 +1,9 @@
+require 'rubygems/tasks/console'
+require 'rubygems/tasks/build'
+require 'rubygems/tasks/install'
+require 'rubygems/tasks/scm'
+require 'rubygems/tasks/scm'
+require 'rubygems/tasks/push'
+require 'rubygems/tasks/release'
+require 'rubygems/tasks/sign'
+require 'rubygems/tasks/tasks'
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/build.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/build.rb
new file mode 100644 (file)
index 0000000..21f29bc
--- /dev/null
@@ -0,0 +1,3 @@
+require 'rubygems/tasks/build/tar'
+require 'rubygems/tasks/build/gem'
+require 'rubygems/tasks/build/zip'
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/build/gem.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/build/gem.rb
new file mode 100644 (file)
index 0000000..c399122
--- /dev/null
@@ -0,0 +1,67 @@
+require 'rubygems/tasks/build/task'
+
+require 'fileutils'
+
+if Gem::VERSION > '2.' then require 'rubygems/package'
+else                        require 'rubygems/builder'
+end
+
+module Gem
+  class Tasks
+    module Build
+      #
+      # The `build:gem` task.
+      #
+      class Gem < Task
+
+        #
+        # Initializes the `build:gem` task.
+        #
+        # @param [Hash] options
+        #   Additional options.
+        #
+        def initialize(options={})
+          super()
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `build:gem` task.
+        #
+        def define
+          build_task :gem
+
+          # backwards compatibility for Gem::PackageTask
+          task :gem => 'build:gem'
+
+          # backwards compatibility for Hoe
+          task :package => 'build:gem'
+        end
+
+        #
+        # Builds the `.gem` package.
+        #
+        # @param [String] path
+        #   The path for the `.gem` package.
+        #
+        # @param [Gem::Specification] gemspec
+        #   The gemspec to build the `.gem` package from.
+        #
+        # @api semipublic
+        #
+        def build(path,gemspec)
+          gem = if ::Gem::VERSION > '2.'
+                  ::Gem::Package.build(gemspec)
+                else
+                  ::Gem::Builder.new(gemspec).build
+                end
+
+          mv gem, Project::PKG_DIR
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/build/tar.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/build/tar.rb
new file mode 100644 (file)
index 0000000..47414b0
--- /dev/null
@@ -0,0 +1,51 @@
+require 'rubygems/tasks/build/task'
+
+require 'set'
+
+module Gem
+  class Tasks
+    module Build
+      #
+      # The `build:tar` task.
+      #
+      class Tar < Task
+
+        #
+        # Initializes the `build:tar` task.
+        #
+        # @param [Hash] options
+        #   Additional options.
+        #
+        def initialize(options={})
+          super()
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `build:tar` task.
+        #
+        def define
+          build_task :tar, 'tar.gz'
+        end
+
+        #
+        # Builds a `.tar.gz` archive.
+        #
+        # @param [String] path
+        #   The path for the `.tar.gz` archive.
+        #
+        # @param [Gem::Specification] gemspec
+        #   The gemspec to generate the archive from.
+        #
+        # @api semipublic
+        #
+        def build(path,gemspec)
+          run 'tar', 'czf', path, *gemspec.files
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/build/task.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/build/task.rb
new file mode 100644 (file)
index 0000000..0ab4184
--- /dev/null
@@ -0,0 +1,67 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    module Build
+      class Task < Tasks::Task
+
+        #
+        # @param [String] path
+        #
+        # @param [Gem::Specification] gemspec
+        #
+        # @abstract
+        #
+        def build(path,gemspec)
+        end
+
+        protected
+
+        #
+        # Defines build task(s) for file type.
+        #
+        # @param [Symbol] name
+        #   The name for the task(s).
+        #
+        # @param [String, Symbol] extname
+        #   The file extension for the resulting files.
+        #
+        # @api semipublic
+        #
+        def build_task(name,extname=name)
+          directory Project::PKG_DIR
+
+          task :validate
+
+          @project.builds.each do |build,packages|
+            namespace :build do
+              namespace name do
+                gemspec = @project.gemspecs[build]
+                path    = packages[extname]
+
+                # define file tasks, so the packages are not needless re-built
+                file(path => [Project::PKG_DIR, *gemspec.files]) do
+                  invoke :validate
+
+                  status "Building #{File.basename(path)} ..."
+
+                  build(path,gemspec)
+                end
+
+                task build => path
+              end
+            end
+
+            task "build:#{build}" => "build:#{name}:#{build}"
+          end
+
+          gemspec_tasks "build:#{name}"
+
+          desc "Builds all packages" unless task?(:build)
+          task :build => "build:#{name}"
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/build/zip.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/build/zip.rb
new file mode 100644 (file)
index 0000000..e5f9a00
--- /dev/null
@@ -0,0 +1,49 @@
+require 'rubygems/tasks/build/task'
+
+module Gem
+  class Tasks
+    module Build
+      #
+      # The `build:zip` task.
+      #
+      class Zip < Task
+
+        #
+        # Initializes the `build:zip` task.
+        #
+        # @param [Hash] options
+        #   Additional options.
+        #
+        def initialize(options={})
+          super()
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `build:zip` task.
+        #
+        def define
+          build_task :zip
+        end
+
+        #
+        # Builds the `.zip` archive.
+        #
+        # @param [String] path
+        #   The path for the `.zip` archive.
+        #
+        # @param [Gem::Specification] gemspec
+        #   The gemspec to build the archive from.
+        #
+        # @api semipublic
+        #
+        def build(path,gemspec)
+          run 'zip', '-q', path, *gemspec.files
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/console.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/console.rb
new file mode 100644 (file)
index 0000000..3283e5b
--- /dev/null
@@ -0,0 +1,99 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    #
+    # The `console` task.
+    #
+    class Console < Task
+
+      # The default Interactive Ruby Console
+      DEFAULT_CONSOLE = 'irb'
+
+      # The default command to run
+      DEFAULT_COMMAND = (ENV['RUBYCONSOLE'] || DEFAULT_CONSOLE)
+
+      # The Ruby Console command
+      attr_accessor :command
+
+      # Additional options for the Ruby Console
+      attr_accessor :options
+
+      #
+      # Initializes the `console` task.
+      #
+      # @param [Hash] options
+      #   Additional options.
+      #
+      # @option options [String] :command (DEFAULT_COMMAND)
+      #   The Ruby Console command to run.
+      #
+      # @option options [Array] :options
+      #   Additional options for the Ruby Console.
+      #
+      def initialize(options={})
+        super()
+
+        @command = options.fetch(:command,DEFAULT_COMMAND)
+        @options = Array(options[:options])
+
+        yield self if block_given?
+        define
+      end
+
+      #
+      # Defines the `console` task.
+      #
+      def define
+        @project.gemspecs.each_key do |name|
+          namespace :console do
+            task(name) { console(name) }
+          end
+        end
+
+        desc "Spawns an Interactive Ruby Console"
+        task :console => "console:#{@project.primary_gemspec}"
+      end
+
+      #
+      # Builds the complete arguments for the console command.
+      #
+      # @param [Symbol, String] name
+      #   The name of the gemspec to load.
+      #
+      # @return [Array<String>]
+      #   The arguments for the console command.
+      #
+      # @api semipublic
+      #
+      def console(name=nil)
+        gemspec = @project.gemspec(name)
+
+        require_paths = gemspec.require_paths
+        require_file  = gemspec.name.gsub('-',File::SEPARATOR)
+
+        arguments = [@command]
+
+        # add -I options for lib/ or ext/ directories
+        arguments.push(*require_paths.map { |dir| "-I#{dir}" })
+
+        # add a -rrubygems to explicitly load rubygems on Ruby 1.8
+        arguments.push('-rrubygems') if RUBY_VERSION < '1.9'
+
+        # add an -r option to require the library
+        arguments.push('-r' + require_file)
+
+        # push on additional options
+        arguments.push(*@options)
+
+        if @project.bundler?
+          # run under `bundle exec`
+          arguments.unshift('bundle', 'exec')
+        end
+
+        return run(*arguments)
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/install.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/install.rb
new file mode 100644 (file)
index 0000000..e4c3107
--- /dev/null
@@ -0,0 +1,62 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    #
+    # The `install` task.
+    #
+    class Install < Task
+
+      #
+      # Initializes the `install` task.
+      #
+      # @param [Hash] options
+      #   Additional options.
+      #
+      def initialize(options={})
+        super()
+
+        yield self if block_given?
+        define
+      end
+
+      #
+      # Defines the `install` task.
+      #
+      def define
+        namespace :install do
+          @project.builds.each do |build,packages|
+            path = packages[:gem]
+
+            task build => path do
+              status "Installing #{File.basename(path)} ..."
+
+              install(path)
+            end
+          end
+        end
+
+        desc "Installs all built gem packages"
+        gemspec_tasks :install
+
+        task :install_gem => :install # backwards compatibility with Hoe
+      end
+
+      #
+      # Pushes the gem by running `gem install`.
+      #
+      # @param [String] path
+      #   The path to the `.gem` file.
+      #
+      # @return [Boolean]
+      #   Specifies whether `gem install` was successful or not.
+      #
+      # @api semipublic
+      #
+      def install(path)
+        run 'gem', 'install', '-q', path
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/printing.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/printing.rb
new file mode 100644 (file)
index 0000000..cb918c8
--- /dev/null
@@ -0,0 +1,98 @@
+module Gem
+  class Tasks
+    #
+    # Provides helper methods for printing messages.
+    #
+    # @api semipublic
+    #
+    module Printing
+
+      # ANSI 'bright' color code
+      ANSI_BRIGHT = "\e[1m"
+
+      # ANSI 'clear' color code
+      ANSI_CLEAR = "\e[0m"
+
+      # ANSI 'green' color code
+      ANSI_GREEN = "\e[32m"
+
+      # ANSI 'yellow' color code
+      ANSI_YELLOW = "\e[33m"
+
+      # ANSI 'red' color code
+      ANSI_RED = "\e[31m"
+
+      # Prefix for all status messages
+      STATUS_PREFIX = if $stdout.tty?
+                        "#{ANSI_GREEN}#{ANSI_BRIGHT}>>>#{ANSI_CLEAR}"
+                      else
+                        ">>>"
+                      end
+
+      # Prefix for all debugging messages
+      DEBUG_PREFIX = if $stderr.tty?
+                        "#{ANSI_YELLOW}#{ANSI_BRIGHT}>>>#{ANSI_CLEAR}"
+                     else
+                       ">>>"
+                     end
+
+      # Prefix for all error messages
+      ERROR_PREFIX = if $stderr.tty?
+                        "#{ANSI_RED}#{ANSI_BRIGHT}!!!#{ANSI_CLEAR}"
+                     else
+                       "!!!"
+                     end
+
+      protected
+
+      #
+      # Prints a status message.
+      #
+      # @param [String] message
+      #   The message to print.
+      #
+      def status(message)
+        if Rake.verbose
+          $stdout.puts "#{STATUS_PREFIX} #{message}"
+        end
+      end
+
+      #
+      # Prints a debugging message.
+      #
+      # @param [String] message
+      #   The message to print.
+      #
+      def debug(message)
+        if (Rake.verbose && Rake.application.options.trace)
+          $stderr.puts "#{DEBUG_PREFIX} #{message}"
+        end
+      end
+
+      #
+      # Prints an error message and exits.
+      #
+      # @param [String] message
+      #   The message to print.
+      #
+      def error(message)
+        $stderr.puts "#{ERROR_PREFIX} #{message}"
+      end
+
+      private
+
+      #
+      # The FileUtils output method.
+      #
+      # @param [String] message
+      #   The FileUtils message to print.
+      #
+      # @since 0.2.1
+      #
+      def fu_output_message(message)
+        debug(message)
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/project.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/project.rb
new file mode 100644 (file)
index 0000000..ffc4b7f
--- /dev/null
@@ -0,0 +1,145 @@
+require 'set'
+
+module Gem
+  class Tasks
+    #
+    # @api semipublic
+    #
+    class Project
+
+      # Supported SCMs and their control directories.
+      SCM_DIRS = {
+        :git => '.git',
+        :hg  => '.hg',
+        :svn => '.svn'
+      }
+
+      # The `pkg/` directory.
+      PKG_DIR = 'pkg'
+
+      #
+      # The project directory.
+      #
+      # @return [String]
+      #   The path to the project.
+      #
+      attr_reader :root
+
+      #
+      # The name of the project.
+      #
+      # @return [String]
+      #   The project name.
+      #
+      attr_reader :name
+
+      #
+      # @return [Symbol, nil]
+      #   The SCM the project is using.
+      #
+      attr_reader :scm
+
+      #
+      # The builds and gemspecs of the project.
+      #
+      # @return [Hash{String => Gem::Specification}]
+      #   The hash of builds and their gemspecs.
+      #
+      attr_reader :gemspecs
+
+      #
+      # The builds and their packages.
+      #
+      # @return [Hash{String => Hash{String => String}}]
+      #   The hash of builds and their respective packages.
+      #
+      attr_reader :builds
+
+      #
+      # The name of the primary gemspec.
+      #
+      # @return [String]
+      #   The gemspec name.
+      #
+      attr_reader :primary_gemspec
+
+      #
+      # Initializes the project.
+      #
+      # @param [String] root
+      #   The root directory of the project.
+      #
+      def initialize(root=Dir.pwd)
+        @root = root
+        @name = File.basename(@root)
+
+        @scm, _ = SCM_DIRS.find do |scm,dir|
+                    File.directory?(File.join(@root,dir))
+                  end
+
+        Dir.chdir(@root) do
+          @gemspecs = Hash[Dir['*.gemspec'].map { |path|
+            [File.basename(path,'.gemspec'), Specification.load(path)]
+          }]
+        end
+
+        @primary_gemspec = if @gemspecs.has_key?(@name)
+                             @name
+                           else
+                             @gemspecs.keys.sort.first
+                           end
+
+        @builds = {}
+
+        @gemspecs.each do |name,gemspec|
+          @builds[name] = Hash.new do |packages,format|
+            packages[format] = File.join(PKG_DIR,"#{gemspec.full_name}.#{format}")
+          end
+        end
+
+        @bundler = File.file?(File.join(@root,'Gemfile'))
+      end
+
+      #
+      # Retrieves a gemspec for the project.
+      #
+      # @param [String] name (@primary_gemspec)
+      #   The gemspec name to retrieve.
+      #
+      # @return [Gem::Specification]
+      #   The requested gemspec.
+      #
+      def gemspec(name=nil)
+        name ||= @primary_gemspec
+
+        unless @gemspecs.has_key?(name)
+          raise(ArgumentError,"unknown gemspec: #{name}")
+        end
+
+        return @gemspecs[name]
+      end
+
+      #
+      # Maps project directories to projects.
+      #
+      # @return [Hash{String => Project}]
+      #   Project directories and project objects.
+      #
+      def self.directories
+        @@directories ||= Hash.new do |hash,key|
+          hash[key] = new(key)
+        end
+      end
+
+      #
+      # Specifies whether the project uses Bundler.
+      #
+      # @return [Boolean]
+      #
+      def bundler?
+        @bundler
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/push.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/push.rb
new file mode 100644 (file)
index 0000000..ed760cd
--- /dev/null
@@ -0,0 +1,79 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    #
+    # The `push` task.
+    #
+    class Push < Task
+
+      # The Gemcutter host to push gems to.
+      attr_accessor :host
+
+      #
+      # Initializes the `push` task.
+      #
+      # @param [Hash] options
+      #   Additional options.
+      #
+      # @option options [String] :host
+      #   The Gemcutter host to push gems to.
+      #
+      def initialize(options={})
+        super()
+
+        @host = options[:host]
+
+        yield self if block_given?
+        define
+      end
+
+      #
+      # Defines the `push` task.
+      #
+      def define
+        task :validate
+
+        namespace :push do
+          @project.builds.each do |build,packages|
+            path = packages[:gem]
+
+            task build => [:validate, path] do
+              if @host
+                status "Pushing #{File.basename(path)} to #{@host} ..."
+              else
+                status "Pushing #{File.basename(path)} ..."
+              end
+
+              push(path)
+            end
+          end
+        end
+
+        gemspec_tasks :push
+
+        # backwards compatibility for Hoe
+        task :publish => :push
+      end
+
+      #
+      # Pushes the gem by running `gem push`.
+      #
+      # @param [String] path
+      #   The path to the `.gem` file.
+      #
+      # @return [Boolean]
+      #   Specifies whether `gem push` was successful or not.
+      #
+      # @api semipublic
+      #
+      def push(path)
+        arguments = ['gem', 'push', path]
+        arguments.push('--host', @host) if @host
+
+        return run(*arguments)
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/release.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/release.rb
new file mode 100644 (file)
index 0000000..588f93e
--- /dev/null
@@ -0,0 +1,49 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    #
+    # The `release` task.
+    #
+    class Release < Task
+
+      #
+      # Initializes the `release` task.
+      #
+      # @param [Hash] options
+      #   Additional options for the `release` task.
+      #
+      def initialize(options={})
+        super()
+
+        yield self if block_given?
+        define
+      end
+
+      #
+      # Defines the `release` task.
+      #
+      def define
+        @project.gemspecs.each_key do |name|
+          task :release => [
+            "build:#{name}",
+            'scm:tag',
+            'scm:push',
+            "push:#{name}",
+            "sign:#{name}"
+          ].select { |name| task?(name) }
+        end
+
+        desc "Performs a release"
+        task :release => [
+          :build,
+          'scm:tag',
+          'scm:push',
+          :push,
+          :sign
+        ].select { |name| task?(name) }
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/scm.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/scm.rb
new file mode 100644 (file)
index 0000000..4c3c655
--- /dev/null
@@ -0,0 +1,3 @@
+require 'rubygems/tasks/scm/status'
+require 'rubygems/tasks/scm/tag'
+require 'rubygems/tasks/scm/push'
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/scm/push.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/scm/push.rb
new file mode 100644 (file)
index 0000000..af4048e
--- /dev/null
@@ -0,0 +1,64 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    module SCM
+      #
+      # The `scm:push` task.
+      #
+      class Push < Task
+
+        #
+        # Initializes the `scm:push` task.
+        #
+        # @param [Hash] options
+        #   Additional options.
+        #
+        def initialize(options={})
+          super()
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `scm:push` task.
+        #
+        def define
+          task :validate
+
+          namespace :scm do
+            task :push => :validate do
+              status "Pushing commits ..."
+
+              unless push!
+                error "Could not push commits"
+              end
+            end
+          end
+        end
+
+        #
+        # Pushes commits.
+        #
+        # @return [Boolean]
+        #   Specifies whether the commits were successfully pushed.
+        #
+        # @api semipublic
+        #
+        def push!
+          case @project.scm
+          when :git
+            run 'git', 'push'
+            run 'git', 'push', '--tags'
+          when :hg 
+            run 'hg', 'push'
+          else
+            true
+          end
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/scm/status.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/scm/status.rb
new file mode 100644 (file)
index 0000000..3c5361f
--- /dev/null
@@ -0,0 +1,80 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    module SCM
+      #
+      # The `scm:status` task.
+      #
+      class Status < Task
+
+        #
+        # Initializes the `status` task.
+        #
+        # @param [Hash] options
+        #   Additional options.
+        #
+        def initialize(options={})
+          super()
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `status` task.
+        #
+        def define
+          namespace :scm do
+            task :status do
+              if dirty?
+                error "Project has uncommitted changes!"
+
+                status
+                abort
+              end
+            end
+          end
+
+          # alias the `validate` task to scm:status
+          task :validate => 'scm:status'
+        end
+
+        #
+        # Checks the status of the project repository.
+        #
+        # @return [Boolean]
+        #   Specifies whether the repository is dirty.
+        #
+        # @api semipublic
+        #
+        # @since 0.2.1
+        #
+        def dirty?
+          status = case @project.scm
+                   when :git then `git status --porcelain --untracked-files=no`
+                   when :hg  then `hg status --quiet`
+                   when :svn then `svn status --quiet`
+                   else            ''
+                   end
+
+          return !status.chomp.empty?
+        end
+
+        #
+        # Displays the status of the project repository.
+        #
+        # @api semipublic
+        #
+        def status
+          case @project.scm
+          when :git then run 'git', 'status', '--untracked-files=no'
+          when :hg  then run 'hg', 'status', '--quiet'
+          when :svn then run 'svn', 'status', '--quiet'
+          end
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/scm/tag.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/scm/tag.rb
new file mode 100644 (file)
index 0000000..51bab3c
--- /dev/null
@@ -0,0 +1,179 @@
+require 'rubygems/tasks/task'
+
+module Gem
+  class Tasks
+    module SCM
+      #
+      # The `scm:tag` task.
+      #
+      class Tag < Task
+
+        # Default format for versions
+        DEFAULT_FORMAT = 'v%s'
+
+        # The format for version tags.
+        #
+        # @return [String, Proc]
+        #   The format String or Proc.
+        #
+        attr_accessor :format
+
+        # Enables or disables PGP signing of tags.
+        # 
+        # @param [Boolean] value
+        #   The new value.
+        #
+        # @since 0.2.0
+        #
+        attr_writer :sign
+
+        #
+        # Initializes the `scm:tag` task.
+        #
+        # @param [Hash] options
+        #   Additional options.
+        #
+        # @option options [String, Proc] :format (DEFAULT_FORMAT)
+        #   The format String or Proc for version tags.
+        #
+        # @option options [Boolean] :sign
+        #   Enables PGP signing of tags.
+        #
+        def initialize(options={})
+          super()
+
+          @format = options.fetch(:format,DEFAULT_FORMAT)
+          @sign   = options[:sign]
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `scm:tag` task.
+        #
+        def define
+          task :validate
+
+          namespace :scm do
+            task :tag, [:name] => :validate do |t,args|
+              tag = (args.name || version_tag(@project.gemspec.version))
+
+              status "Tagging #{tag} ..."
+
+              unless tag!(tag)
+                error "Could not create tag #{tag}"
+              end
+            end
+          end
+        end
+
+        #
+        # Formats the version into a version tag.
+        #
+        # @param [String] version
+        #   The version to be formatted.
+        #
+        # @return [String]
+        #   The tag for the version.
+        #
+        # @raise [TypeError]
+        #   {#format} was not a String or a Proc.
+        #
+        # @api semipublic
+        #
+        def version_tag(version)
+          case @format
+          when String
+            (@format % version)
+          when Proc
+            @format[version]
+          else
+            raise(TypeError,"tag format must be a String or Proc")
+          end
+        end
+
+        #
+        # Indicates whether new tags will be signed.
+        #
+        # @return [Boolean]
+        #   Specifies whether new tags will be signed.
+        #
+        # @note
+        #   If {#sign=} has not been set, {#sign?} will determine if tag signing
+        #   has been enabled globally by calling the following commands:
+        #
+        #   * Git: `git config user.signingkey`
+        #   * Mercurial: `hg showconfig extensions hgext gpg`
+        #
+        # @api semipublic
+        #
+        # @since 0.2.0
+        #
+        def sign?
+          if @sign.nil?
+            @sign = case @project.scm
+                    when :git
+                      !`git config user.signingkey`.chomp.empty?
+                    when :hg
+                      !`hg showconfig extensions.hgext.gpg`.empty?
+                    else
+                      false
+                    end
+          end
+
+          return @sign
+        end
+
+        #
+        # Creates a tag.
+        #
+        # @param [String] name
+        #   The name of the tag.
+        #
+        # @return [Boolean]
+        #   Specifies whether the tag was successfully created.
+        #
+        # @api semipublic
+        #
+        def tag!(name)
+          message = "Tagging #{name}"
+
+          case @project.scm
+          when :git then
+            arguments = ['-m', message]
+            arguments << '-s' if sign?
+            arguments << name
+
+            run 'git', 'tag', *arguments
+          when :hg  then
+            if sign?
+              # sign the change-set, then tag the release
+              run 'hg', 'sign', '-m', "Signing #{name}"
+            end
+
+            run 'hg', 'tag', '-m', message, name
+          when :svn
+            branch   = File.basename(@project.root)
+            tags_dir = if branch == 'trunk'
+                         # we are in trunk/
+                         File.join('..','tags')
+                       else
+                         # must be within branches/$name/
+                         File.join('..','..','tags')
+                       end
+
+            tag_dir = File.join(tag_dirs,name)
+
+            run 'svn', 'mkdir', '--parents', tag_dir
+            run 'svn', 'cp', '*', tag_dir
+            run 'svn', 'commit', '-m', message, tag_dir
+          else
+            true
+          end
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/sign.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/sign.rb
new file mode 100644 (file)
index 0000000..75abcf5
--- /dev/null
@@ -0,0 +1,2 @@
+require 'rubygems/tasks/sign/checksum'
+require 'rubygems/tasks/sign/pgp'
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/sign/checksum.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/sign/checksum.rb
new file mode 100644 (file)
index 0000000..a045f5a
--- /dev/null
@@ -0,0 +1,113 @@
+require 'rubygems/tasks/sign/task'
+
+require 'digest'
+
+module Gem
+  class Tasks
+    module Sign
+      #
+      # The `sign:checksum` task.
+      #
+      class Checksum < Task
+
+        # Enables or disables MD5 checksums.
+        attr_writer :md5
+
+        # Enables or disables SHA1 checksums.
+        attr_writer :sha1
+
+        # Enables or disables SHA2 checksums.
+        attr_writer :sha2
+
+        # Enables or disables SHA512 checksums.
+        attr_writer :sha512
+
+        #
+        # Initializes the `sign:checksum` task.
+        #
+        # @param [Hash] options
+        #   Digest options.
+        #
+        # @option options [Boolean] :md5 (true)
+        #   Specifies whether MD5 checksums are enabled.
+        #
+        # @option options [Boolean] :sha1 (true)
+        #   Specifies whether SHA1 checksums are enabled.
+        #
+        # @option options [Boolean] :sha2 (false)
+        #   Specifies whether SHA2 checksums are enabled.
+        #
+        # @option options [Boolean] :sha512 (false)
+        #   Specifies whether SHA512 checksums are enabled.
+        #
+        def initialize(options={})
+          super()
+
+          @md5    = options.fetch(:md5,   true)
+          @sha1   = options.fetch(:sha1,  true)
+          @sha2   = options.fetch(:sha2,  false)
+          @sha512 = options.fetch(:sha512,false)
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Specifies whether MD5 checksums are enabled.
+        #
+        # @return [Boolean]
+        #
+        def md5?; @md5; end
+
+        #
+        # Specifies whether SHA1 checksums are enabled.
+        #
+        # @return [Boolean]
+        #
+        def sha1?; @sha1; end
+
+        #
+        # Specifies whether SHA2 checksums are enabled.
+        #
+        # @return [Boolean]
+        #
+        def sha2?; @sha2; end
+
+        #
+        # Specifies whether SHA512 checksums are enabled.
+        #
+        # @return [Boolean]
+        #
+        def sha512?; @sha512; end
+
+        #
+        # Defines the `sign:checksum` tasks.
+        #
+        def define
+          sign_task :checksum
+          task      :checksum => 'sign:checksum'
+        end
+
+        #
+        # Prints the checksums of a package.
+        #
+        # @param [String] path
+        #   The path to the package.
+        #
+        # @api semipublic
+        #
+        def sign(path)
+          status "Checksums for #{File.basename(path)}:"
+
+          puts
+          puts "  md5:    #{Digest::MD5.file(path)}"    if @md5
+          puts "  sha1:   #{Digest::SHA1.file(path)}"   if @sha1
+          puts "  sha2:   #{Digest::SHA2.file(path)}"   if @sha2
+          puts "  sha512: #{Digest::SHA512.file(path)}" if @sha512
+          puts
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/sign/pgp.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/sign/pgp.rb
new file mode 100644 (file)
index 0000000..66fa111
--- /dev/null
@@ -0,0 +1,50 @@
+require 'rubygems/tasks/sign/task'
+
+module Gem
+  class Tasks
+    module Sign
+      #
+      # The `sign:pgp` task.
+      #
+      class PGP < Task
+
+        #
+        # Initializes the `sign` task.
+        #
+        # @param [Hash] options
+        #   Digest options.
+        #
+        def initialize(options={})
+          super()
+
+          yield self if block_given?
+          define
+        end
+
+        #
+        # Defines the `sign:pgp` task.
+        #
+        def define
+          sign_task :pgp
+
+          task :pgp => 'sign:pgp'
+        end
+
+        #
+        # PGP signs a package.
+        #
+        # @param [String] path
+        #   The path to the package.
+        #
+        # @api semipublic
+        #
+        def sign(path)
+          status "Signing #{File.basename(path)} ..."
+
+          run 'gpg', '--sign', '--detach-sign', '--armor', path
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/sign/task.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/sign/task.rb
new file mode 100644 (file)
index 0000000..2f33d9b
--- /dev/null
@@ -0,0 +1,58 @@
+require 'rubygems/tasks/task'
+
+require 'digest'
+
+module Gem
+  class Tasks
+    module Sign
+      class Task < Tasks::Task
+
+        #
+        # Signs a package.
+        #
+        # @param [String] path
+        #   The path to the package.
+        #
+        # @abstract
+        #
+        def sign(path)
+        end
+
+        protected
+
+        #
+        # Defines signing tasks for the various packages.
+        #
+        # @param [Symbol] name
+        #   The name for the `sign:` task.
+        #
+        # @api semipublic
+        #
+        def sign_task(name)
+          @project.builds.each do |build,packages|
+            packages.each do |format,path|
+              namespace :sign do
+                namespace name do 
+                  namespace build do
+                    task format => path do
+                      sign(path)
+                    end
+                  end
+                end
+              end
+            end
+
+            multi_task "sign:#{name}:#{build}", packages.keys
+
+            task "sign:#{name}"  => "sign:#{name}:#{build}"
+            task "sign:#{build}" => "sign:#{name}:#{build}"
+
+            desc "Signs all packages" unless task?(:sign)
+            task :sign           => "sign:#{name}:#{build}"
+          end
+        end
+
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/task.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/task.rb
new file mode 100644 (file)
index 0000000..0c63e2c
--- /dev/null
@@ -0,0 +1,153 @@
+require 'rubygems/tasks/project'
+require 'rubygems/tasks/printing'
+
+require 'rake/tasklib'
+
+module Gem
+  class Tasks
+    class Task < Rake::TaskLib
+
+      include Printing
+
+      #
+      # Project metadata.
+      #
+      # @return [Project]
+      #
+      attr_reader :project
+
+      #
+      # Initializes the task.
+      #
+      def initialize
+        @project = Project.directories[Dir.pwd]
+      end
+
+      protected
+
+      #
+      # Runs a command.
+      #
+      # @param [String] command
+      #   The command to run.
+      #
+      # @param [Array<String>] arguments
+      #   Additional arguments for the command.
+      #
+      # @return [Boolean]
+      #   Specifies whether the command was successful.
+      #
+      # @api semipublic
+      #
+      def run(command,*arguments)
+        show_command = [command, *arguments].join(' ')
+
+        debug show_command
+
+        unless system(command,*arguments)
+          error "Command failed: #{show_command}"
+          abort
+        end
+
+        return true
+      end
+
+      #
+      # Runs a `gem` command.
+      #
+      # @param [String] command
+      #   The `gem` command to run.
+      #
+      # @param [Array<String>] arguments
+      #   Additional arguments for the command.
+      #
+      # @return [Boolean]
+      #   Specifies whether the command was successful.
+      #
+      # @api semipublic
+      #
+      def gem(command,*arguments)
+        run 'gem', command, *arguments
+      end
+
+      #
+      # Runs a `bundle` command.
+      #
+      # @param [String] command
+      #   The `bundle` command to run.
+      #
+      # @param [Array<String>] arguments
+      #   Additional arguments for the command.
+      #
+      # @return [Boolean]
+      #   Specifies whether the command was successful.
+      #
+      # @api semipublic
+      #
+      def bundle(command,*arguments)
+        run 'bundler', command, *arguments
+      end
+
+      #
+      # Determines if a task was defined.
+      #
+      # @param [Symbol, String] name
+      #   The task name to search for.
+      #
+      # @return [Boolean]
+      #   Specifies whether the task was defined.
+      #
+      # @api semipublic
+      #
+      def task?(name)
+        Rake::Task.task_defined?(name)
+      end
+
+      #
+      # Explicitly invokes a task.
+      #
+      # @param [Symbol, String] name
+      #   The name of the task.
+      #
+      # @api semipublic
+      #
+      # @since 0.2.2
+      #
+      def invoke(name)
+        Rake.application[name].invoke
+      end
+
+      #
+      # Defines a task that will invoke one or all of the specifies tasks
+      # within the namespace.
+      #
+      # @param [String] prefix
+      #   The namespace of the sub-tasks to call.
+      #
+      # @param [Array<Symbol>] names
+      #   The names of the sub-tasks.
+      #
+      # @example
+      #   gemspec_tasks 'pkg:tar'
+      #
+      # @api semipublic
+      #
+      def multi_task(prefix,names)
+        task prefix => names.map { |name| "#{prefix}:#{name}" }
+      end
+
+      #
+      # Defines a task that will execute tasks for each gemspec.
+      #
+      # @param [Symbol, String] name
+      #   The name for the task.
+      #
+      # @api semipublic
+      #
+      def gemspec_tasks(name)
+        multi_task name, @project.gemspecs.keys
+      end
+
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/lib/rubygems/tasks/tasks.rb b/ruby-rubygems-tasks/lib/rubygems/tasks/tasks.rb
new file mode 100644 (file)
index 0000000..55e3709
--- /dev/null
@@ -0,0 +1,147 @@
+require 'rubygems/tasks/console'
+require 'rubygems/tasks/build'
+require 'rubygems/tasks/install'
+require 'rubygems/tasks/scm'
+require 'rubygems/tasks/push'
+require 'rubygems/tasks/release'
+require 'rubygems/tasks/sign'
+
+require 'rake/tasklib'
+require 'ostruct'
+
+module Gem
+  #
+  # Defines basic Rake tasks for managing and releasing projects:
+  #
+  # * {Build::Gem build:gem}
+  # * {Build::Tar build:tar}
+  # * {Build::Zip build:zip}
+  # * {SCM::Status scm:status}
+  # * {SCM::Push scm:push}
+  # * {SCM::Tag scm:tag}
+  # * {Console console}
+  # * {Install install}
+  # * {Push push}
+  # * {Release release}
+  # * {Sign::Checksum sign:checksum}
+  # * {Sign::PGP sign:pgp}
+  #
+  class Tasks
+
+    #
+    # The `build` tasks.
+    #
+    # @return [OpenStruct]
+    #   The collection of `build` tasks.
+    #
+    attr_reader :build
+
+    #
+    # The `scm` tasks.
+    #
+    # @return [OpenStruct]
+    #   The collection of `scm` tasks.
+    #
+    attr_reader :scm
+
+    #
+    # The `sign` tasks.
+    #
+    # @return [OpenStruct]
+    #   The collection of `sign` tasks.
+    #
+    attr_reader :sign
+
+    # The {Console console} task.
+    attr_reader :console
+
+    # The {Install install} task.
+    attr_reader :install
+
+    # The {Push push} task.
+    attr_reader :push
+
+    # The {Release release} task.
+    attr_reader :release
+
+    #
+    # Initializes the project tasks.
+    #
+    # @param [Hash{Symbol => Hash}] options
+    #   Enables or disables individual tasks.
+    #
+    # @option options [Hash{Symbol => Boolean}] :build
+    #   Enables or disables the `build` tasks.
+    #
+    # @option options [Hash{Symbol => Boolean}] :scm
+    #   Enables or disables the `scm` tasks.
+    #
+    # @option options [Boolean] :console (true)
+    #   Enables or disables the {Console console} task.
+    #
+    # @option options [Boolean] :install (true)
+    #   Enables or disables the {Install install} task.
+    #
+    # @option options [Boolean] :push (true)
+    #   Enables or disables the {Push push} task.
+    #
+    # @option options [Boolean] :release (true)
+    #   Enables or disables the {Release release} task.
+    #
+    # @option options [Hash{Symbol => Boolean}] :sign
+    #   Enables or disables the `sign` tasks.
+    #
+    # @yield [tasks]
+    #   If a block is given, it will be passed the newly created tasks,
+    #   before they are fully defined.
+    #
+    # @yieldparam [Tasks] tasks
+    #   The newly created tasks.
+    #
+    # @example Enables building of `.gem` and `.tar.gz` packages:
+    #   Gem::Tasks.new(:build => {:gem => true, :tar => true})
+    #
+    # @example Disables pushing `.gem` packages to [rubygems.org](rubygems.org):
+    #   Gem::Tasks.new(:push => false)
+    #
+    # @example Configures the version tag format:
+    #   Gem::Tasks.new do |tasks|
+    #     tasks.scm.tag.format = "release-%s"
+    #   end
+    #
+    def initialize(options={})
+      build_options = options.fetch(:build,{})
+      scm_options   = options.fetch(:scm,{})
+      sign_options  = options.fetch(:sign,{})
+
+      @scm   = OpenStruct.new
+      @build = OpenStruct.new
+      @sign  = OpenStruct.new
+
+      if build_options
+        @build.gem = (Build::Gem.new if build_options.fetch(:gem,true))
+        @build.tar = (Build::Tar.new if build_options[:tar])
+        @build.zip = (Build::Zip.new if build_options[:zip])
+      end
+
+      if scm_options
+        @scm.status = (SCM::Status.new if scm_options.fetch(:status,true))
+        @scm.tag    = (SCM::Tag.new    if scm_options.fetch(:tag,true))
+        @scm.push   = (SCM::Push.new   if scm_options.fetch(:push,true))
+      end
+
+      if sign_options
+        @sign.checksum = (Sign::Checksum.new if sign_options[:checksum])
+        @sign.pgp      = (Sign::PGP.new      if sign_options[:pgp])
+      end
+
+      @console = (Console.new if options.fetch(:console,true))
+      @install = (Install.new if options.fetch(:install,true))
+      @push    = (Push.new    if options.fetch(:push,true))
+      @release = (Release.new if options.fetch(:release,true))
+
+      yield self if block_given?
+    end
+
+  end
+end
diff --git a/ruby-rubygems-tasks/metadata.yml b/ruby-rubygems-tasks/metadata.yml
new file mode 100644 (file)
index 0000000..3cec9ae
--- /dev/null
@@ -0,0 +1,146 @@
+--- !ruby/object:Gem::Specification 
+name: rubygems-tasks
+version: !ruby/object:Gem::Version 
+  hash: 31
+  prerelease: 
+  segments: 
+  - 0
+  - 2
+  - 4
+  version: 0.2.4
+platform: ruby
+authors: 
+- Postmodern
+autorequire: 
+bindir: bin
+cert_chain: []
+
+date: 2013-04-08 00:00:00 Z
+dependencies: 
+- !ruby/object:Gem::Dependency 
+  name: rspec
+  prerelease: false
+  requirement: &id001 !ruby/object:Gem::Requirement 
+    none: false
+    requirements: 
+    - - ~>
+      - !ruby/object:Gem::Version 
+        hash: 11
+        segments: 
+        - 2
+        - 4
+        version: "2.4"
+  type: :development
+  version_requirements: *id001
+- !ruby/object:Gem::Dependency 
+  name: yard
+  prerelease: false
+  requirement: &id002 !ruby/object:Gem::Requirement 
+    none: false
+    requirements: 
+    - - ~>
+      - !ruby/object:Gem::Version 
+        hash: 5
+        segments: 
+        - 0
+        - 7
+        version: "0.7"
+  type: :development
+  version_requirements: *id002
+description: Agnostic and unobtrusive Rake tasks for managing and releasing Ruby Gems.
+email: postmodern.mod3@gmail.com
+executables: []
+
+extensions: []
+
+extra_rdoc_files: 
+- ChangeLog.md
+- LICENSE.txt
+- README.md
+files: 
+- .document
+- .gitignore
+- .rspec
+- .yardopts
+- ChangeLog.md
+- LICENSE.txt
+- README.md
+- Rakefile
+- gemspec.yml
+- lib/rubygems/tasks.rb
+- lib/rubygems/tasks/build.rb
+- lib/rubygems/tasks/build/gem.rb
+- lib/rubygems/tasks/build/tar.rb
+- lib/rubygems/tasks/build/task.rb
+- lib/rubygems/tasks/build/zip.rb
+- lib/rubygems/tasks/console.rb
+- lib/rubygems/tasks/install.rb
+- lib/rubygems/tasks/printing.rb
+- lib/rubygems/tasks/project.rb
+- lib/rubygems/tasks/push.rb
+- lib/rubygems/tasks/release.rb
+- lib/rubygems/tasks/scm.rb
+- lib/rubygems/tasks/scm/push.rb
+- lib/rubygems/tasks/scm/status.rb
+- lib/rubygems/tasks/scm/tag.rb
+- lib/rubygems/tasks/sign.rb
+- lib/rubygems/tasks/sign/checksum.rb
+- lib/rubygems/tasks/sign/pgp.rb
+- lib/rubygems/tasks/sign/task.rb
+- lib/rubygems/tasks/task.rb
+- lib/rubygems/tasks/tasks.rb
+- rubygems-tasks.gemspec
+- spec/console_spec.rb
+- spec/install_spec.rb
+- spec/project_spec.rb
+- spec/push_spec.rb
+- spec/rake_context.rb
+- spec/scm/push_spec.rb
+- spec/scm/status_spec.rb
+- spec/scm/tag_spec.rb
+- spec/sign/pgp_spec.rb
+- spec/spec_helper.rb
+- spec/tasks_spec.rb
+homepage: https://github.com/postmodern/rubygems-tasks#readme
+licenses: []
+
+post_install_message: 
+rdoc_options: []
+
+require_paths: 
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement 
+  none: false
+  requirements: 
+  - - ">="
+    - !ruby/object:Gem::Version 
+      hash: 3
+      segments: 
+      - 0
+      version: "0"
+required_rubygems_version: !ruby/object:Gem::Requirement 
+  none: false
+  requirements: 
+  - - ">="
+    - !ruby/object:Gem::Version 
+      hash: 3
+      segments: 
+      - 0
+      version: "0"
+requirements: []
+
+rubyforge_project: 
+rubygems_version: 1.8.24
+signing_key: 
+specification_version: 3
+summary: Rake tasks for managing and releasing Ruby Gems.
+test_files: 
+- spec/console_spec.rb
+- spec/install_spec.rb
+- spec/project_spec.rb
+- spec/push_spec.rb
+- spec/scm/push_spec.rb
+- spec/scm/status_spec.rb
+- spec/scm/tag_spec.rb
+- spec/sign/pgp_spec.rb
+- spec/tasks_spec.rb
diff --git a/ruby-rubygems-tasks/rubygems-tasks.gemspec b/ruby-rubygems-tasks/rubygems-tasks.gemspec
new file mode 100644 (file)
index 0000000..28880d8
--- /dev/null
@@ -0,0 +1,109 @@
+# encoding: utf-8
+
+require 'yaml'
+
+Gem::Specification.new do |gemspec|
+  files = if File.directory?('.git')
+            `git ls-files`.split($/)
+          elsif File.directory?('.hg')
+            `hg manifest`.split($/)
+          elsif File.directory?('.svn')
+            `svn ls -R`.split($/).select { |path| File.file?(path) }
+          else
+            Dir['{**/}{.*,*}'].select { |path| File.file?(path) }
+          end
+
+  filter_files = lambda { |paths|
+    case paths
+    when Array
+      (files & paths)
+    when String
+      (files & Dir[paths])
+    end
+  }
+
+  version = {
+    :file     => 'lib/rubygems/tasks/version.rb',
+    :constant => 'Gem::Tasks::VERSION'
+  }
+
+  defaults = {
+    'name'            => File.basename(File.dirname(__FILE__)),
+    'files'           => files,
+    'require_paths'   => ['ext', 'lib'].select { |dir| File.directory?(dir) },
+    'executables'     => filter_files['bin/*'].map { |path| File.basename(path) },
+    'test_files'      => filter_files['{test/{**/}*_test.rb,spec/{**/}*_spec.rb}'],
+    'extra_doc_files' => filter_files['*.{txt,rdoc,md,markdown,tt,textile}']
+  }
+
+  metadata = defaults.merge(YAML.load_file('gemspec.yml'))
+
+  gemspec.name    = metadata['name']
+  gemspec.version = if metadata['version']
+                      metadata['version']
+                    else
+                      $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
+
+                      require version[:file]
+                      eval(version[:constant])
+                    end
+
+  gemspec.summary     = metadata.fetch('summary',metadata['description'])
+  gemspec.description = metadata.fetch('description',metadata['summary'])
+
+  gemspec.licenses = Array(metadata['license'])
+  gemspec.authors  = Array(metadata['authors'])
+
+  gemspec.email    = metadata['email']
+  gemspec.homepage = metadata['homepage']
+
+  gemspec.require_paths = Array(metadata['require_paths'])
+  gemspec.files         = filter_files[metadata['files']]
+  gemspec.executables   = metadata['executables']
+  gemspec.extensions    = metadata['extensions']
+
+  if Gem::VERSION < '1.7.'
+    gemspec.default_executable = gemspec.executables.first
+  end
+
+  gemspec.test_files       = filter_files[metadata['test_files']]
+  gemspec.extra_rdoc_files = Array(metadata['extra_doc_files'])
+
+  gemspec.post_install_message = metadata['post_install_message']
+  gemspec.requirements         = metadata['requirements']
+
+  if gemspec.respond_to?(:required_ruby_version=)
+    gemspec.required_ruby_version = metadata['required_ruby_version']
+  end
+
+  if gemspec.respond_to?(:required_rubygems_version=)
+    gemspec.required_rubygems_version = metadata['required_ruby_version']
+  end
+
+  parse_versions = lambda { |versions|
+    case versions
+    when Array
+      versions.map { |v| v.to_s }
+    when String
+      versions.split(/,\s*/)
+    end
+  }
+
+  if metadata['dependencies']
+    metadata['dependencies'].each do |name,versions|
+      gemspec.add_dependency(name,parse_versions[versions])  
+    end
+  end
+
+  if metadata['runtime_dependencies']
+    metadata['runtime_dependencies'].each do |name,versions|
+      gemspec.add_runtime_dependency(name,parse_versions[versions])  
+    end
+  end
+
+  if metadata['development_dependencies']
+    metadata['development_dependencies'].each do |name,versions|
+      gemspec.add_development_dependency(name,parse_versions[versions])  
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/console_spec.rb b/ruby-rubygems-tasks/spec/console_spec.rb
new file mode 100644 (file)
index 0000000..76cb8da
--- /dev/null
@@ -0,0 +1,78 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/console'
+
+describe Gem::Tasks::Console do
+  describe "#console" do
+    include_context "rake"
+
+    if RUBY_VERSION < '1.9'
+      let(:default_options) { %w[-Ilib -rrubygems -rrubygems/tasks] }
+    else
+      let(:default_options) { %w[-Ilib -rrubygems/tasks]            }
+    end
+
+    let(:custom_command)  { 'ripl'             }
+    let(:custom_options)  { %w[-Ivendor -rfoo] }
+
+    context "defaults" do
+      it "should run `irb`" do
+        subject.should_receive(:run).with('irb',*default_options)
+
+        subject.console
+      end
+
+      context "when project.bundler? == true" do
+        it "should use `bundle exec`" do
+          subject.project.stub!(:bundler?).and_return(true)
+          subject.should_receive(:run).with(
+            'bundle', 'exec', 'irb', *default_options
+          )
+
+          subject.console
+        end
+      end
+    end
+
+    context "with custom command" do
+      subject { described_class.new(:command => custom_command) }
+
+      it "should run the custom console" do
+        subject.should_receive(:run).with(custom_command,*default_options)
+
+        subject.console
+      end
+
+      context "when project.bundler? == true" do
+        it "should use `bundle exec`" do
+          subject.project.stub!(:bundler?).and_return(true)
+          subject.should_receive(:run).with(
+            'bundle', 'exec', custom_command, *default_options
+          )
+
+          subject.console
+        end
+      end
+    end
+
+    context "with custom options" do
+      subject { described_class.new(:options => custom_options) }
+
+      it "should pass custom options to `irb`" do
+        subject.should_receive(:run).with('irb', *(default_options + custom_options))
+
+        subject.console
+      end
+
+      context "when project.bundler? == true" do
+        it "should use `bundle exec ...`" do
+          subject.project.stub!(:bundler?).and_return(true)
+          subject.should_receive(:run).with('bundle', 'exec', 'irb', *(default_options + custom_options))
+
+          subject.console
+        end
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/install_spec.rb b/ruby-rubygems-tasks/spec/install_spec.rb
new file mode 100644 (file)
index 0000000..803c3ef
--- /dev/null
@@ -0,0 +1,16 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/install'
+
+describe Gem::Tasks::Install do
+  describe "#install" do
+    let(:path) { 'pkg/foo-1.2.3.gem' }
+
+    it "should use `gem install -q`" do
+      subject.should_receive(:run).with('gem', 'install', '-q', path)
+
+      subject.install(path)
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/project_spec.rb b/ruby-rubygems-tasks/spec/project_spec.rb
new file mode 100644 (file)
index 0000000..6e71878
--- /dev/null
@@ -0,0 +1,159 @@
+require 'spec_helper'
+require 'rubygems/tasks/project'
+
+describe Gem::Tasks::Project do
+  let(:rubygems_project) do
+    described_class.new(PROJECT_DIRS['rubygems-project'])
+  end
+
+  let(:rubygems_multi_project) do
+    described_class.new(PROJECT_DIRS['rubygems-multi-project'])
+  end
+
+  let(:bundler_project) do
+    described_class.new(PROJECT_DIRS['bundler-project'])
+  end
+
+  describe "directories" do
+    it "should map paths to #{described_class} instances" do
+      directory = PROJECT_DIRS['rubygems-project']
+      project   = described_class.directories[directory]
+
+      project.root.should == directory
+    end
+  end
+
+  describe "#name" do
+    subject { rubygems_project }
+
+    it "should use the name of the directory" do
+      subject.name.should == 'rubygems-project'
+    end
+  end
+
+  describe "#scm" do
+    subject { bundler_project }
+
+    it "should detect the SCM used" do
+      subject.scm.should == :git
+    end
+  end
+
+  describe "#gemspecs" do
+    context "with single-gemspec project" do
+      subject { rubygems_project }
+
+      it "should load the single-gemspec" do
+        subject.gemspecs.values.map(&:name).should == %w[rubygems-project]
+      end
+    end
+
+    context "with multi-gemspec project" do
+      subject { rubygems_multi_project }
+
+      it "should load all gemspecs" do
+        subject.gemspecs.values.map(&:name).should =~ %w[
+          rubygems-project
+          rubygems-project-lite
+        ]
+      end
+    end
+  end
+
+  describe "#primary_gemspec" do
+    context "with single-gemspec project" do
+      subject { rubygems_project }
+
+      it "should match the directory name to the gemspec" do
+        subject.primary_gemspec.should == subject.name
+      end
+    end
+
+    context "with multi-gemspec project" do
+      subject { rubygems_multi_project }
+
+      it "should pick the first gemspec" do
+        subject.primary_gemspec.should == 'rubygems-project'
+      end
+    end
+  end
+
+  describe "#gemspec" do
+    context "with single-gemspec project" do
+      subject { rubygems_project }
+
+      it "should default the directory name to the gemspec" do
+        subject.gemspec.name.should == subject.name
+      end
+
+      it "should raise an ArgumentError for unknown gemspec names" do
+        lambda { subject.gemspec('foo') }.should raise_error(ArgumentError)
+      end
+    end
+
+    context "with multi-gemspec project" do
+      subject { rubygems_multi_project }
+
+      it "should default the first gemspec" do
+        subject.gemspec.name.should == 'rubygems-project'
+      end
+
+      it "should allow accessing alternate gemspecs" do
+        alternate = 'rubygems-project-lite'
+
+        subject.gemspec(alternate).name.should == alternate
+      end
+    end
+  end
+
+  describe "#builds" do
+    subject { rubygems_multi_project }
+
+    it "should group builds by gemspec name" do
+      subject.builds.keys.should =~ subject.gemspecs.keys
+    end
+
+    it "should map a package format to a pkg/ path" do
+      packages = subject.builds['rubygems-project']
+
+      packages['tar.gz'].should == 'pkg/rubygems-project-1.2.3.tar.gz'
+    end
+
+    context "with single-gemspec project" do
+      subject { rubygems_project }
+
+      it "should only have a key for the single-gemspec" do
+        subject.builds.keys.should == %w[rubygems-project]
+      end
+    end
+
+    context "with multi-gemspec project" do
+      subject { rubygems_multi_project }
+
+      it "should have keys for each gemspec" do
+        subject.builds.keys.should =~ %w[
+          rubygems-project
+          rubygems-project-lite
+        ]
+      end
+    end
+  end
+
+  describe "#bundler?" do
+    context "with Bundler" do
+      subject { bundler_project }
+
+      it "should detect the 'Gemfile' file" do
+        subject.bundler?.should be_true
+      end
+    end
+
+    context "without Bundler" do
+      subject { rubygems_project }
+
+      it "should be false" do
+        subject.bundler?.should be_false
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/push_spec.rb b/ruby-rubygems-tasks/spec/push_spec.rb
new file mode 100644 (file)
index 0000000..69ec268
--- /dev/null
@@ -0,0 +1,32 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/push'
+
+describe Gem::Tasks::Push do
+  describe "#push" do
+    include_context "rake"
+
+    let(:path) { 'pkg/foo-1.2.3.gem' }
+
+    context "defaults" do
+      it "should use `gem push`" do
+        subject.should_receive(:run).with('gem', 'push', path)
+
+        subject.push(path)
+      end
+    end
+
+    context "with custom :host" do
+      let(:host) { 'internal.company.com' }
+
+      subject { described_class.new(:host => host) }
+
+      it "should include the --host option" do
+        subject.should_receive(:run).with('gem', 'push', path, '--host', host)
+
+        subject.push(path)
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/rake_context.rb b/ruby-rubygems-tasks/spec/rake_context.rb
new file mode 100644 (file)
index 0000000..a36691b
--- /dev/null
@@ -0,0 +1,10 @@
+require 'rake'
+
+shared_context "rake" do
+  let(:rake)   { Rake::Application.new   }
+
+  before(:all) do
+    Rake.verbose(false)
+    Rake.application = rake
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/scm/push_spec.rb b/ruby-rubygems-tasks/spec/scm/push_spec.rb
new file mode 100644 (file)
index 0000000..b445df4
--- /dev/null
@@ -0,0 +1,35 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/scm/push'
+
+describe Gem::Tasks::SCM::Push do
+  describe "#push!" do
+    context "git" do
+      it "should run `git push --tags`" do
+        subject.project.stub!(:scm).and_return(:git)
+        subject.should_receive(:run).with('git', 'push')
+        subject.should_receive(:run).with('git', 'push', '--tags')
+
+        subject.push!
+      end
+    end
+
+    context "hg" do
+      it "should run `hg push`" do
+        subject.project.stub!(:scm).and_return(:hg)
+        subject.should_receive(:run).with('hg', 'push')
+
+        subject.push!
+      end
+    end
+
+    context "otherwise" do
+      it "should return true" do
+        subject.project.stub!(:scm).and_return(:svn)
+
+        subject.push!.should == true
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/scm/status_spec.rb b/ruby-rubygems-tasks/spec/scm/status_spec.rb
new file mode 100644 (file)
index 0000000..d521235
--- /dev/null
@@ -0,0 +1,50 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/scm/status'
+
+describe Gem::Tasks::SCM::Status do
+  describe "#status" do
+    context "git" do
+      include_context "rake"
+
+      it "should run `git status --untracked-files=no`" do
+        subject.project.stub!(:scm).and_return(:git)
+
+        subject.should_receive(:run).with(
+          'git', 'status', '--untracked-files=no'
+        )
+
+        subject.status
+      end
+    end
+
+    context "hg" do
+      include_context "rake"
+
+      it "should run `hg status --quiet`" do
+        subject.project.stub!(:scm).and_return(:hg)
+
+        subject.should_receive(:run).with(
+          'hg', 'status', '--quiet'
+        )
+
+        subject.status
+      end
+    end
+
+    context "svn" do
+      include_context "rake"
+
+      it "should run `svn status --quiet`" do
+        subject.project.stub!(:scm).and_return(:svn)
+
+        subject.should_receive(:run).with(
+          'svn', 'status', '--quiet'
+        )
+
+        subject.status
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/scm/tag_spec.rb b/ruby-rubygems-tasks/spec/scm/tag_spec.rb
new file mode 100644 (file)
index 0000000..8cb2995
--- /dev/null
@@ -0,0 +1,116 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/scm/tag'
+
+describe Gem::Tasks::SCM::Tag do
+  let(:version) { '1.2.3' }
+
+  describe "#version_tag" do
+    context "defaults" do
+      include_context "rake"
+
+      it "should have a 'v' prefix" do
+        subject.version_tag(version).should == "v#{version}"
+      end
+    end
+
+    context "with format String" do
+      include_context "rake"
+
+      let(:format) { 'release-%s' }
+
+      subject { described_class.new(:format => format) }
+
+      it "should apply the format String to the version" do
+        subject.version_tag(version).should == "release-#{version}"
+      end
+    end
+
+    context "with format Proc" do
+      let(:format) { proc { |ver| "REL_" + ver.tr('.','_') } }
+
+      subject { described_class.new(:format => format) }
+
+      it "should call the format Proc with the version" do
+        subject.version_tag(version).should == "REL_1_2_3"
+      end
+    end
+  end
+
+  describe "#tag!" do
+    let(:name)    { "v#{version}"        }
+    let(:message) { "Tagging #{name}"    }
+
+    context "git" do
+      context "without signing" do
+        include_context "rake"
+
+        subject { described_class.new(:sign => false) }
+
+        it "should run `git tag`" do
+          subject.project.stub!(:scm).and_return(:git)
+
+          subject.should_receive(:run).with(
+            'git', 'tag', '-m', message, name
+          )
+
+          subject.tag!(name)
+        end
+      end
+
+      context "signing" do
+        include_context "rake"
+
+        subject { described_class.new(:sign => true) }
+
+        it "should run `git tag -s`" do
+          subject.project.stub!(:scm).and_return(:git)
+
+          subject.should_receive(:run).with(
+            'git', 'tag', '-m', message, '-s', name
+          )
+
+          subject.tag!(name)
+        end
+      end
+    end
+
+    context "hg" do
+      context "without signing" do
+        include_context "rake"
+
+        subject { described_class.new(:sign => false) }
+
+        it "should run `hg tag`" do
+          subject.project.stub!(:scm).and_return(:hg)
+
+          subject.should_receive(:run).with(
+            'hg', 'tag', '-m', message, name
+          )
+
+          subject.tag!(name)
+        end
+      end
+
+      context "with signing" do
+        include_context "rake"
+
+        subject { described_class.new(:sign => true) }
+
+        it "should run `hg sign` then `hg tag`" do
+          subject.project.stub!(:scm).and_return(:hg)
+
+          subject.should_receive(:run).with(
+            'hg', 'sign', '-m', "Signing #{name}"
+          )
+          subject.should_receive(:run).with(
+            'hg', 'tag', '-m', message, name
+          )
+
+          subject.tag!(name)
+        end
+      end
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/sign/pgp_spec.rb b/ruby-rubygems-tasks/spec/sign/pgp_spec.rb
new file mode 100644 (file)
index 0000000..28b15ad
--- /dev/null
@@ -0,0 +1,20 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/sign/pgp'
+
+describe Gem::Tasks::Sign::PGP do
+  describe "#sign" do
+    include_context "rake"
+
+    let(:path) { File.join('pkg','foo-1.2.3.gem') }
+
+    it "should run `gpg --sign --detach-sign --armor ...`" do
+      subject.should_receive(:run).with(
+        'gpg', '--sign', '--detach-sign', '--armor', path
+      )
+
+      subject.sign(path)
+    end
+  end
+end
diff --git a/ruby-rubygems-tasks/spec/spec_helper.rb b/ruby-rubygems-tasks/spec/spec_helper.rb
new file mode 100644 (file)
index 0000000..e94e172
--- /dev/null
@@ -0,0 +1,12 @@
+gem 'rspec', '~> 2.4'
+require 'rspec'
+
+PROJECTS_DIR = File.join('data','projects')
+PROJECT_DIRS = lambda { |name| File.join(PROJECTS_DIR,name) }
+
+unless File.directory?(PROJECTS_DIR)
+  abort "Please run `rake data:projects` before running the specs!"
+end
+
+# clear the $RUBYCONSOLE env variable
+ENV['RUBYCONSOLE'] = nil
diff --git a/ruby-rubygems-tasks/spec/tasks_spec.rb b/ruby-rubygems-tasks/spec/tasks_spec.rb
new file mode 100644 (file)
index 0000000..c66eb5a
--- /dev/null
@@ -0,0 +1,127 @@
+require 'spec_helper'
+require 'rake_context'
+
+require 'rubygems/tasks/tasks'
+
+describe Gem::Tasks do
+  describe "#initialize" do
+    context "default options" do
+      include_context "rake"
+
+      its(:build)      { should be_kind_of(OpenStruct)             }
+      its('build.gem') { should be_kind_of(Gem::Tasks::Build::Gem) }
+      its('build.tar') { should be_nil                             }
+      its('build.zip') { should be_nil                             }
+
+      its(:scm)         { should be_kind_of(OpenStruct)              }
+      its('scm.status') { should be_kind_of(Gem::Tasks::SCM::Status) }
+      its('scm.push')   { should be_kind_of(Gem::Tasks::SCM::Push)   }
+      its('scm.tag')    { should be_kind_of(Gem::Tasks::SCM::Tag)    }
+
+      its(:sign)           { should be_kind_of(OpenStruct) }
+      its('sign.checksum') { should be_nil                 }
+      its('sign.pgp')      { should be_nil                 }
+
+      its(:console) { should be_kind_of(Gem::Tasks::Console) }
+      its(:install) { should be_kind_of(Gem::Tasks::Install) }
+      its(:push)    { should be_kind_of(Gem::Tasks::Push)    }
+      its(:release) { should be_kind_of(Gem::Tasks::Release) }
+    end
+
+    context ":build => {:gem => false}" do
+      include_context "rake"
+
+      subject { described_class.new(:build => {:gem => false}) }
+
+      its('build.gem') { should be_nil }
+    end
+
+    context ":build => {:tar => true}" do
+      include_context "rake"
+
+      subject { described_class.new(:build => {:tar => true}) }
+
+      its('build.tar') { should be_kind_of(Gem::Tasks::Build::Tar) }
+    end
+
+    context ":build => {:zip => true}" do
+      include_context "rake"
+
+      subject { described_class.new(:build => {:zip => true}) }
+
+      its('build.zip') { should be_kind_of(Gem::Tasks::Build::Zip) }
+    end
+
+    context ":scm => {:status => false}" do
+      include_context "rake"
+
+      subject { described_class.new(:scm => {:status => false}) }
+
+      its('scm.status') { should be_nil }
+    end
+
+    context ":scm => {:push => false}" do
+      include_context "rake"
+
+      subject { described_class.new(:scm => {:push => false}) }
+
+      its('scm.push') { should be_nil }
+    end
+
+    context ":scm => {:tag => false}" do
+      include_context "rake"
+
+      subject { described_class.new(:scm => {:tag => false}) }
+
+      its('scm.tag') { should be_nil }
+    end
+
+    context ":sign => {:checksum => true}" do
+      include_context "rake"
+
+      subject { described_class.new(:sign => {:checksum => true}) }
+
+      its('sign.checksum') { should be_kind_of(Gem::Tasks::Sign::Checksum) }
+    end
+
+    context ":sign => {:pgp => true}" do
+      include_context "rake"
+
+      subject { described_class.new(:sign => {:pgp => true}) }
+
+      its('sign.pgp') { should be_kind_of(Gem::Tasks::Sign::PGP) }
+    end
+
+    context ":console => false" do
+      include_context "rake"
+
+      subject { described_class.new(:console => false) }
+
+      its(:console) { should be_nil }
+    end
+
+    context ":install => false" do
+      include_context "rake"
+
+      subject { described_class.new(:install => false) }
+
+      its(:install) { should be_nil }
+    end
+
+    context ":push => false" do
+      include_context "rake"
+
+      subject { described_class.new(:push => false) }
+
+      its(:push) { should be_nil }
+    end
+
+    context ":release => false" do
+      include_context "rake"
+
+      subject { described_class.new(:release => false) }
+
+      its(:release) { should be_nil }
+    end
+  end
+end