gem_publisher 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/gem_publisher/builder.rb +13 -0
- data/lib/gem_publisher/cli_facade.rb +17 -0
- data/lib/gem_publisher/git_remote.rb +26 -0
- data/lib/gem_publisher/publisher.rb +41 -0
- data/lib/gem_publisher/pusher.rb +20 -0
- data/lib/gem_publisher/version.rb +3 -0
- data/lib/gem_publisher.rb +8 -0
- data/test/builder_test.rb +16 -0
- data/test/cli_facade_test.rb +28 -0
- data/test/common.rb +11 -0
- data/test/data/gem_build +4 -0
- data/test/data/tags +10 -0
- data/test/gem_publisher_test.rb +44 -0
- data/test/git_remote_test.rb +32 -0
- data/test/integration_test.rb +26 -0
- metadata +60 -0
@@ -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,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
|
data/test/data/gem_build
ADDED
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
|