gem_publisher 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ require "gem_publisher/cli_facade"
2
+
3
+ module GemPublisher
4
+ class Builder
5
+ def initialize(cli_facade = CliFacade.new)
6
+ @cli_facade = cli_facade
7
+ end
8
+
9
+ def build(gemspec)
10
+ @cli_facade.execute("gem", "build", gemspec)[/File:\s+(.+)/, 1]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require "shellwords"
2
+ require "open3"
3
+
4
+ module GemPublisher
5
+ class CliFacade
6
+ Error = Class.new(RuntimeError)
7
+
8
+ def execute(*arguments)
9
+ cmd = Shellwords.join(arguments)
10
+ stdout_str, stderr_str, status = Open3.capture3(cmd)
11
+ if status.exitstatus > 0
12
+ raise Error, stderr_str
13
+ end
14
+ stdout_str
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require "gem_publisher/cli_facade"
2
+
3
+ module GemPublisher
4
+ class GitRemote
5
+ def initialize(name = "origin", cli_facade = CliFacade.new)
6
+ @remote_name = name
7
+ @cli_facade = cli_facade
8
+ end
9
+
10
+ def tags
11
+ s = git("ls-remote", "--tags", @remote_name)
12
+ s.scan(%r{refs/tags/(.+)}).map(&:first).reject { |t| t =~ /\^\{\}$/ }
13
+ end
14
+
15
+ def add_tag(tag_name, commit_ish = "HEAD")
16
+ sha1 = git("rev-parse", commit_ish)
17
+ git "update-ref", "refs/tags/#{tag_name}", sha1
18
+ git "push", @remote_name, "tag", tag_name
19
+ end
20
+
21
+ private
22
+ def git(*args)
23
+ @cli_facade.execute(*["git"] + args)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,41 @@
1
+ require "gem_publisher/git_remote"
2
+ require "gem_publisher/builder"
3
+ require "gem_publisher/pusher"
4
+
5
+ module GemPublisher
6
+ class Publisher
7
+ attr_accessor :git_remote, :builder, :pusher
8
+
9
+ def initialize(gemspec, version)
10
+ @gemspec = gemspec
11
+ @version = version
12
+ @git_remote = GitRemote.new
13
+ @builder = Builder.new
14
+ @pusher = Pusher.new
15
+ end
16
+
17
+ def publish_if_updated(method)
18
+ return unless version_bumped?
19
+ gem = @builder.build(@gemspec)
20
+ @git_remote.add_tag "v#@version"
21
+ @pusher.push gem, method
22
+ end
23
+
24
+ private
25
+ def version_bumped?
26
+ last_release = @git_remote.tags.
27
+ select { |t| t =~ /^v\d+(\.\d+)+/ }.
28
+ map { |t| t.scan(/\d+/).map(&:to_i) }.
29
+ sort.last
30
+ this_release = @version.split(/\./).map(&:to_i)
31
+ this_release != last_release
32
+ end
33
+
34
+ def tag_remote
35
+ return
36
+ sha1 = `git rev-parse HEAD`
37
+ system "git update-ref refs/tags/v#@version #{sha1}"
38
+ system "git push origin tag v#@version"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ require "gem_publisher/cli_facade"
2
+
3
+ module GemPublisher
4
+ class Pusher
5
+ def initialize(cli_facade = CliFacade.new)
6
+ @cli_facade = cli_facade
7
+ end
8
+
9
+ PUSH_METHODS = {
10
+ :rubygems => %w[gem push],
11
+ :gemfury => %w[fury push]
12
+ }
13
+
14
+ def push(gem, method)
15
+ push_command = PUSH_METHODS[method] or raise "Unknown Gem push method #{method.inspect}."
16
+ @cli_facade.execute *push_command + [gem]
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,3 @@
1
+ module GemPublisher
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "gem_publisher/publisher"
2
+ require "gem_publisher/version"
3
+
4
+ module GemPublisher
5
+ def self.publish_if_updated(gemspec, version, method=:rubygems)
6
+ Publisher.new(gemspec, version).publish_if_updated(method)
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path("../common", __FILE__)
2
+ require "gem_publisher/builder"
3
+
4
+ module GemPublisher
5
+ class BuilderTest < MiniTest::Unit::TestCase
6
+ def test_should_build_gem_and_return_filename
7
+ cli_facade = mock
8
+ cli_facade.expects(:execute).
9
+ with("gem", "build", "foo.gemspec").
10
+ returns(data_file("gem_build"))
11
+
12
+ builder = Builder.new(cli_facade)
13
+ assert_equal "test_gem-0.0.2.gem", builder.build("foo.gemspec")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path("../common", __FILE__)
2
+ require "gem_publisher/cli_facade"
3
+
4
+ module GemPublisher
5
+ class CliFacadeTest < MiniTest::Unit::TestCase
6
+ def test_should_raise_exception_if_command_failed
7
+ status = stub(exitstatus: 1)
8
+ Open3.stubs(:capture3).returns(["stdout", "stderr", status])
9
+ assert_raises CliFacade::Error do
10
+ CliFacade.new.execute("status")
11
+ end
12
+ end
13
+
14
+ def test_should_return_stdout_if_command_succeeded
15
+ status = stub(exitstatus: 0)
16
+ Open3.stubs(:capture3).returns(["stdout", "stderr", status])
17
+ assert_equal "stdout", CliFacade.new.execute("status")
18
+ end
19
+
20
+ def test_should_escape_and_pass_in_all_commands
21
+ status = stub(exitstatus: 0)
22
+ Open3.expects(:capture3).
23
+ with("foo bar \\*").
24
+ returns(["stdout", "stderr", status])
25
+ CliFacade.new.execute("foo", "bar", "*")
26
+ end
27
+ end
28
+ end
data/test/common.rb ADDED
@@ -0,0 +1,11 @@
1
+ lib = File.expand_path("../../lib", __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require "minitest/autorun"
5
+ require "mocha"
6
+
7
+ class MiniTest::Unit::TestCase
8
+ def data_file(name)
9
+ File.read(File.expand_path("../data/#{name}", __FILE__))
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ Successfully built RubyGem
2
+ Name: test_gem
3
+ Version: 0.0.2
4
+ File: test_gem-0.0.2.gem
data/test/data/tags ADDED
@@ -0,0 +1,10 @@
1
+ 41c5b8ad5122893bb63754c098ee25b93cce20e1 refs/tags/v0.0.10
2
+ a3762f17d9f234c058a9f8194154513a89f0a19b refs/tags/v0.0.10^{}
3
+ c7b78dd34aebdce17fae1773ca0a854de3da32a3 refs/tags/v0.0.11
4
+ 5294fac0c70956209494b69bc1a8c38192f6a931 refs/tags/v0.0.11^{}
5
+ 4775fe5cc621a2955b4438d0747069bf6fc56b02 refs/tags/v0.0.6
6
+ e0911ed33423177183b88d5f3a339f680aa24564 refs/tags/v0.0.6^{}
7
+ 6cad8efbe5df65a3aaf5608f24a5bfb99973cb4a refs/tags/v0.0.7
8
+ 3fd61ea34c30022889bfa2856dc807d98c15e0f5 refs/tags/v0.0.7^{}
9
+ 2cce20d85a69974be0c5fc7fd5af207062690089 refs/tags/v0.0.9
10
+ f15a4d4a7726c7c624a33e727fcdbabb3938ac02 refs/tags/v0.0.9^{}
@@ -0,0 +1,44 @@
1
+ require File.expand_path("../common", __FILE__)
2
+ require "gem_publisher/publisher"
3
+
4
+ module GemPublisher
5
+ class PublisherTest < MiniTest::Unit::TestCase
6
+ def test_should_not_do_anything_if_version_has_not_changed
7
+ p = Publisher.new("foo.gemspec", "0.0.2")
8
+ p.builder = mock
9
+ p.builder.expects(:build).never
10
+ p.pusher = mock
11
+ p.pusher.expects(:push).never
12
+ p.git_remote = mock
13
+ p.git_remote.stubs(:tags).returns(%w[v0.0.1 v0.0.2])
14
+ p.git_remote.expects(:add_tag).never
15
+ p.publish_if_updated(:bogus)
16
+ end
17
+
18
+ def test_should_build_and_tag_and_publish_if_version_has_changed
19
+ p = Publisher.new("foo.gemspec", "0.0.3")
20
+ p.builder = mock
21
+ p.builder.expects(:build).
22
+ with("foo.gemspec").
23
+ returns("foo-0.0.3.gem")
24
+ p.pusher = mock
25
+ p.pusher.expects(:push).with("foo-0.0.3.gem", :method)
26
+ p.git_remote = mock
27
+ p.git_remote.stubs(:tags).returns(%w[v0.0.1 v0.0.2])
28
+ p.git_remote.expects(:add_tag).with("v0.0.3")
29
+ p.publish_if_updated(:method)
30
+ end
31
+
32
+ def test_should_build_and_tag_and_publish_if_there_is_no_released_version
33
+ p = Publisher.new("foo.gemspec", "0.0.3")
34
+ p.builder = mock
35
+ p.builder.expects(:build).returns("foo-0.0.3.gem")
36
+ p.pusher = mock
37
+ p.pusher.expects(:push)
38
+ p.git_remote = mock
39
+ p.git_remote.stubs(:tags).returns([])
40
+ p.git_remote.expects(:add_tag).with("v0.0.3")
41
+ p.publish_if_updated(:method)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path("../common", __FILE__)
2
+ require "gem_publisher/git_remote"
3
+
4
+ module GemPublisher
5
+ class GitRemoteTest < MiniTest::Unit::TestCase
6
+ def test_should_list_remote_tags
7
+ cli_facade = mock
8
+ cli_facade.stubs(:execute).
9
+ with("git", "ls-remote", "--tags", "origin").
10
+ returns(data_file("tags"))
11
+
12
+ remote = GitRemote.new("origin", cli_facade)
13
+ expected = %w[v0.0.10 v0.0.11 v0.0.6 v0.0.7 v0.0.9]
14
+ assert_equal expected.sort, remote.tags.sort
15
+ end
16
+
17
+ def test_should_push_tag_to_remote
18
+ cli_facade = mock
19
+ sha1 = "5294fac0c70956209494b69bc1a8c38192f6a931"
20
+ cli_facade.stubs(:execute).
21
+ with("git", "rev-parse", "HEAD").
22
+ returns(sha1)
23
+ cli_facade.expects(:execute).
24
+ with("git", "update-ref", "refs/tags/nameoftag", sha1)
25
+ cli_facade.expects(:execute).
26
+ with("git", "push", "origin", "tag", "nameoftag")
27
+
28
+ remote = GitRemote.new("origin", cli_facade)
29
+ remote.add_tag("nameoftag")
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path("../common", __FILE__)
2
+ require "gem_publisher"
3
+
4
+ module GemPublisher
5
+ class IntegrationTest < MiniTest::Unit::TestCase
6
+ def setup
7
+ Open3.stubs(:capture3)
8
+ end
9
+
10
+ def expect_cli(command, response = "")
11
+ Open3.expects(:capture3).
12
+ with(command).
13
+ returns([response, "", stub(exitstatus: 0)])
14
+ end
15
+
16
+ def test_should_build_and_tag_and_publish
17
+ expect_cli "git ls-remote --tags origin", data_file("tags")
18
+ expect_cli "gem build example.gemspec", data_file("gem_build")
19
+ expect_cli "git rev-parse HEAD", "1234abcd"
20
+ expect_cli "git update-ref refs/tags/v1.0.0 1234abcd"
21
+ expect_cli "git push origin tag v1.0.0"
22
+ expect_cli "gem push test_gem-0.0.2.gem"
23
+ GemPublisher.publish_if_updated "example.gemspec", "1.0.0"
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gem_publisher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul Battley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-10 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Automatically build, tag, and push a gem when its version has been updated.
15
+ email: pbattley@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/gem_publisher/git_remote.rb
21
+ - lib/gem_publisher/builder.rb
22
+ - lib/gem_publisher/cli_facade.rb
23
+ - lib/gem_publisher/pusher.rb
24
+ - lib/gem_publisher/publisher.rb
25
+ - lib/gem_publisher/version.rb
26
+ - lib/gem_publisher.rb
27
+ - test/builder_test.rb
28
+ - test/git_remote_test.rb
29
+ - test/data/tags
30
+ - test/data/gem_build
31
+ - test/cli_facade_test.rb
32
+ - test/gem_publisher_test.rb
33
+ - test/integration_test.rb
34
+ - test/common.rb
35
+ homepage: http://github.com/threedaymonk/gem_publisher
36
+ licenses: []
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 1.8.24
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Automatically build, tag, and push gems
59
+ test_files: []
60
+ has_rdoc: true