gem-release 1.0.0 → 2.0.0.dev.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +13 -0
- data/Gemfile.lock +72 -0
- data/{lib/gem_release/templates/LICENSE → MIT-LICENSE.md} +3 -2
- data/README.md +646 -0
- data/README.md.erb +159 -0
- data/TODO.txt +194 -0
- data/lib/gem/release.rb +13 -0
- data/lib/gem/release/cmds.rb +16 -0
- data/lib/gem/release/cmds/base.rb +101 -0
- data/lib/gem/release/cmds/bootstrap.rb +222 -0
- data/lib/gem/release/cmds/bump.rb +165 -0
- data/lib/gem/release/cmds/gemspec.rb +85 -0
- data/lib/gem/release/cmds/release.rb +100 -0
- data/lib/gem/release/cmds/runner.rb +52 -0
- data/lib/gem/release/cmds/tag.rb +93 -0
- data/lib/gem/release/config.rb +42 -0
- data/lib/gem/release/config/env.rb +49 -0
- data/lib/gem/release/config/files.rb +35 -0
- data/lib/gem/release/context.rb +76 -0
- data/lib/gem/release/context/gem.rb +28 -0
- data/lib/gem/release/context/gemspec.rb +41 -0
- data/lib/gem/release/context/paths.rb +87 -0
- data/lib/gem/release/context/system.rb +36 -0
- data/lib/gem/release/data.rb +60 -0
- data/lib/gem/release/files/template.rb +61 -0
- data/lib/gem/release/files/template/context.rb +30 -0
- data/lib/gem/release/files/templates.rb +59 -0
- data/lib/gem/release/files/templates/group.rb +47 -0
- data/lib/gem/release/files/version.rb +68 -0
- data/lib/gem/release/helper.rb +45 -0
- data/lib/gem/release/helper/hash.rb +35 -0
- data/lib/gem/release/helper/string.rb +43 -0
- data/lib/gem/release/support/gem_command.rb +67 -0
- data/lib/gem/release/support/registry.rb +59 -0
- data/lib/gem/release/templates/.gitignore +8 -0
- data/lib/gem/release/templates/Gemfile +3 -0
- data/lib/gem/release/templates/gemspec +19 -0
- data/lib/gem/release/templates/licenses/mit.md +21 -0
- data/lib/gem/release/templates/licenses/mpl-2.md +373 -0
- data/lib/gem/release/templates/main.rb +1 -0
- data/lib/gem/release/templates/rspec/.rspec +3 -0
- data/lib/gem/release/templates/rspec/spec/spec_helper.rb +4 -0
- data/lib/gem/release/templates/travis/.travis.yml +1 -0
- data/lib/gem/release/templates/version.rb +1 -0
- data/lib/gem/release/version.rb +5 -0
- data/lib/gem/release/version/number.rb +102 -0
- data/lib/rubygems/commands/bootstrap_command.rb +4 -93
- data/lib/rubygems/commands/bump_command.rb +4 -110
- data/lib/rubygems/commands/gemspec_command.rb +5 -29
- data/lib/rubygems/commands/release_command.rb +4 -70
- data/lib/rubygems/commands/tag_command.rb +5 -46
- data/lib/rubygems_plugin.rb +8 -2
- metadata +56 -83
- data/lib/core_ext/hash/symbolize_keys.rb +0 -13
- data/lib/core_ext/kernel/silence.rb +0 -18
- data/lib/core_ext/string/camelize.rb +0 -5
- data/lib/gem_release.rb +0 -10
- data/lib/gem_release/command_options.rb +0 -31
- data/lib/gem_release/configuration.rb +0 -33
- data/lib/gem_release/gemspec_template.rb +0 -35
- data/lib/gem_release/helpers.rb +0 -104
- data/lib/gem_release/template.rb +0 -52
- data/lib/gem_release/templates/Gemfile +0 -3
- data/lib/gem_release/templates/README.md +0 -1
- data/lib/gem_release/templates/Rakefile +0 -10
- data/lib/gem_release/templates/gemspec +0 -18
- data/lib/gem_release/templates/gitignore +0 -25
- data/lib/gem_release/templates/test/test_helper.rb +0 -2
- data/lib/gem_release/templates/version.rb +0 -12
- data/lib/gem_release/version.rb +0 -3
- data/lib/gem_release/version_file.rb +0 -115
- data/lib/gem_release/version_template.rb +0 -14
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'gem/release/cmds/base'
|
2
|
+
require 'rubygems/commands/build_command'
|
3
|
+
require 'rubygems/commands/push_command'
|
4
|
+
|
5
|
+
module Gem
|
6
|
+
module Release
|
7
|
+
module Cmds
|
8
|
+
class Release < Base
|
9
|
+
summary 'Releases one or all gems in this directory.'
|
10
|
+
|
11
|
+
description <<~str
|
12
|
+
Builds one or many gems from the given gemspec(s), pushes them to rubygems.org
|
13
|
+
(or another, compatible host), and removes the left over gem file.
|
14
|
+
|
15
|
+
Optionally invoke `gem tag`.
|
16
|
+
|
17
|
+
If no argument is given the first gemspec's name is assumed as the gem name.
|
18
|
+
If one or many arguments are given then these will be used. If `--recurse` is
|
19
|
+
given then all gem names from all gemspecs in this directory or any of its
|
20
|
+
subdirectories will be used.
|
21
|
+
str
|
22
|
+
|
23
|
+
arg :gem_name, 'name of the gem (optional, will use the first gemspec, or all gemspecs if --recurse is given)'
|
24
|
+
|
25
|
+
DESCR = {
|
26
|
+
host: 'Push to a compatible host other than rubygems.org',
|
27
|
+
key: 'Use the API key from ~/.gem/credentials',
|
28
|
+
tag: 'Shortcut for running the `gem tag` command',
|
29
|
+
recurse: 'Recurse into directories that contain gemspec files'
|
30
|
+
}
|
31
|
+
|
32
|
+
opt '-h', '--host HOST', DESCR[:host] do |value|
|
33
|
+
opts[:host] = value
|
34
|
+
end
|
35
|
+
|
36
|
+
opt '-k', '--key KEY', DESCR[:key] do |value|
|
37
|
+
opts[:key] = value
|
38
|
+
end
|
39
|
+
|
40
|
+
opt '-t', '--tag', DESCR[:tag] do |value|
|
41
|
+
opts[:tag] = value
|
42
|
+
end
|
43
|
+
|
44
|
+
opt '--recurse', DESCR[:recurse] do |value|
|
45
|
+
opts[:recurse] = value
|
46
|
+
end
|
47
|
+
|
48
|
+
MSGS = {
|
49
|
+
release: 'Releasing %s with version %s',
|
50
|
+
build: 'Building %s',
|
51
|
+
push: 'Pushing %s',
|
52
|
+
cleanup: 'Deleting left over gem file %s'
|
53
|
+
}
|
54
|
+
|
55
|
+
CMDS = {
|
56
|
+
cleanup: 'rm -f %s'
|
57
|
+
}
|
58
|
+
|
59
|
+
def run
|
60
|
+
in_gem_dirs do
|
61
|
+
release
|
62
|
+
end
|
63
|
+
tag if opts[:tag]
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def release
|
69
|
+
announce :release, gem.name, gem.version
|
70
|
+
build
|
71
|
+
push
|
72
|
+
ensure
|
73
|
+
cleanup
|
74
|
+
end
|
75
|
+
|
76
|
+
def tag
|
77
|
+
Tag.new(context, args, opts).run
|
78
|
+
end
|
79
|
+
|
80
|
+
def build
|
81
|
+
gem_cmd :build, gem.spec_filename
|
82
|
+
end
|
83
|
+
|
84
|
+
def push
|
85
|
+
gem_cmd :push, gem.filename, *push_args
|
86
|
+
end
|
87
|
+
|
88
|
+
def push_args
|
89
|
+
args = [:key, :host].map { |opt| ["--#{opt}", opts[opt]] if opts[opt] }
|
90
|
+
args << "--quiet" if quiet?
|
91
|
+
args.compact.flatten
|
92
|
+
end
|
93
|
+
|
94
|
+
def cleanup
|
95
|
+
cmd :cleanup, gem.filename
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'gem/release/context'
|
2
|
+
|
3
|
+
module Gem
|
4
|
+
module Release
|
5
|
+
module Cmds
|
6
|
+
class Runner < Struct.new(:context, :name, :args, :opts)
|
7
|
+
def run
|
8
|
+
run_cmd
|
9
|
+
success
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def run_cmd
|
15
|
+
const.new(context.class.new, args, opts).run
|
16
|
+
end
|
17
|
+
|
18
|
+
def const
|
19
|
+
Base[name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def opts
|
23
|
+
except(super, :args, :build_args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def args
|
27
|
+
super.select { |arg| arg.is_a?(String) && arg[0] != '-' }
|
28
|
+
end
|
29
|
+
|
30
|
+
def success
|
31
|
+
context.announce "All is good, thanks my friend." unless quiet?
|
32
|
+
end
|
33
|
+
|
34
|
+
def quiet?
|
35
|
+
opts[:quiet] || opts[:silent]
|
36
|
+
end
|
37
|
+
|
38
|
+
def opts
|
39
|
+
@opts ||= config.merge(super)
|
40
|
+
end
|
41
|
+
|
42
|
+
def config
|
43
|
+
context.config.for(name.to_sym)
|
44
|
+
end
|
45
|
+
|
46
|
+
def except(hash, *keys)
|
47
|
+
hash.reject { |key, _| keys.include?(key) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'gem/release/cmds/base'
|
2
|
+
|
3
|
+
module Gem
|
4
|
+
module Release
|
5
|
+
module Cmds
|
6
|
+
class Tag < Base
|
7
|
+
summary "Tags the HEAD commit with the gem's current version."
|
8
|
+
|
9
|
+
description <<~str
|
10
|
+
Creates an annotated tag for the current HEAD commit, using the gem's
|
11
|
+
current version.
|
12
|
+
|
13
|
+
Optionally pushes the tag to the origin repository.
|
14
|
+
|
15
|
+
If one or many arguments are given then gemspecs with the same names
|
16
|
+
will be searched, and the working directory changed to their respective
|
17
|
+
directories. If `--recurse` is given then the directories all gem names from
|
18
|
+
all gemspecs in this directory or any of its subdirectories will be used.
|
19
|
+
This assumes that these directories are separate git repositories.
|
20
|
+
|
21
|
+
The tag name will be `v[version]`. For example, if the current version is
|
22
|
+
`1.0.0`, then The tag is created using the command `git tag -am "tag v1.0.0"
|
23
|
+
v1.0.0`.
|
24
|
+
str
|
25
|
+
|
26
|
+
DEFAULTS = {
|
27
|
+
push: true,
|
28
|
+
remote: 'origin'
|
29
|
+
}
|
30
|
+
|
31
|
+
DESCR = {
|
32
|
+
push: 'Push tag to the remote git repository',
|
33
|
+
remote: 'Git remote to push to (defaults to origin)',
|
34
|
+
}
|
35
|
+
|
36
|
+
opt '-p', '--[no]-push', DESCR[:push] do
|
37
|
+
opts[:push] = true
|
38
|
+
end
|
39
|
+
|
40
|
+
opt '--remote REMOTE', DESCR[:remote] do |value|
|
41
|
+
opts[:remote] = value
|
42
|
+
end
|
43
|
+
|
44
|
+
MSGS = {
|
45
|
+
tag: 'Tagging %s as version %s',
|
46
|
+
git_tag: 'Creating git tag %s',
|
47
|
+
git_push: 'Pushing tags to the %s git repository',
|
48
|
+
no_remote: 'Cannot push to missing git remote %s',
|
49
|
+
}
|
50
|
+
|
51
|
+
CMDS = {
|
52
|
+
git_tag: 'git tag -am "tag %s" %s',
|
53
|
+
git_push: 'git push --tags %s'
|
54
|
+
}
|
55
|
+
|
56
|
+
def run
|
57
|
+
in_gem_dirs do
|
58
|
+
announce :tag, gem.name, gem.version
|
59
|
+
validate
|
60
|
+
tag
|
61
|
+
push if opts[:push]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def validate
|
68
|
+
abort :no_remote, remote if push? && !git_remotes.include?(remote)
|
69
|
+
end
|
70
|
+
|
71
|
+
def tag
|
72
|
+
cmd :git_tag, tag_name, tag_name
|
73
|
+
end
|
74
|
+
|
75
|
+
def push
|
76
|
+
cmd :git_push, remote
|
77
|
+
end
|
78
|
+
|
79
|
+
def tag_name
|
80
|
+
"v#{gem.version}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def push?
|
84
|
+
opts[:push] || opts[:push_commit]
|
85
|
+
end
|
86
|
+
|
87
|
+
def remote
|
88
|
+
opts[:remote]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'gem/release/config/env'
|
2
|
+
require 'gem/release/config/files'
|
3
|
+
require 'gem/release/helper/hash'
|
4
|
+
|
5
|
+
module Gem
|
6
|
+
module Release
|
7
|
+
class Config
|
8
|
+
include Helper::Hash
|
9
|
+
|
10
|
+
attr_reader :opts
|
11
|
+
|
12
|
+
SOURCES = [Env, Files]
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@opts = load
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](key)
|
19
|
+
opts[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def for(key)
|
23
|
+
common.merge(self[key] || {})
|
24
|
+
end
|
25
|
+
|
26
|
+
def common
|
27
|
+
opts.reject { |_, value| value.is_a?(Hash) }
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def load
|
33
|
+
opts = sources.map(&:load)
|
34
|
+
opts.inject { |one, other| deep_merge(one, other) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def sources
|
38
|
+
SOURCES.map(&:new)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'gem/release/helper/hash'
|
2
|
+
|
3
|
+
module Gem
|
4
|
+
module Release
|
5
|
+
class Config
|
6
|
+
class Env
|
7
|
+
include Helper::Hash
|
8
|
+
|
9
|
+
PREFIX = 'GEM_RELEASE_'
|
10
|
+
TRUE = /^(true|yes|on)$/
|
11
|
+
FALSE = /^(false|no|off)$/
|
12
|
+
|
13
|
+
def load
|
14
|
+
opts = vars.map { |key, value| to_hash(keys_for(key), cast(value)) }
|
15
|
+
opts = opts.inject { |one, other| deep_merge(one, other) }
|
16
|
+
opts || {}
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def vars
|
22
|
+
ENV.select { |key, _| key.start_with?(PREFIX) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def keys_for(key)
|
26
|
+
key.sub(PREFIX, '').split('_').map(&:downcase).map(&:to_sym)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_hash(keys, value)
|
30
|
+
keys = keys.reverse
|
31
|
+
keys.inject(keys.shift => value) { |value, key| { key => value } }
|
32
|
+
end
|
33
|
+
|
34
|
+
def cast(value)
|
35
|
+
case value
|
36
|
+
when TRUE
|
37
|
+
true
|
38
|
+
when FALSE
|
39
|
+
false
|
40
|
+
when ''
|
41
|
+
false
|
42
|
+
else
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'gem/release/helper/hash'
|
3
|
+
|
4
|
+
module Gem
|
5
|
+
module Release
|
6
|
+
class Config
|
7
|
+
class Files
|
8
|
+
include Helper::Hash
|
9
|
+
|
10
|
+
PATHS = %w(
|
11
|
+
./.gem_release/config.yml
|
12
|
+
./.gem_release.yml
|
13
|
+
~/.gem_release/config.yml
|
14
|
+
~/.gem_release.yml
|
15
|
+
)
|
16
|
+
|
17
|
+
def load
|
18
|
+
return {} unless path
|
19
|
+
symbolize_keys(YAML.load_file(path) || {})
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def path
|
25
|
+
@path ||= paths.first
|
26
|
+
end
|
27
|
+
|
28
|
+
def paths
|
29
|
+
paths = PATHS.map { |path| File.expand_path(path) }
|
30
|
+
paths.select { |path| File.exists?(path) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'gem/release/context/gem'
|
2
|
+
require 'gem/release/context/paths'
|
3
|
+
require 'gem/release/context/system'
|
4
|
+
|
5
|
+
module Gem
|
6
|
+
module Release
|
7
|
+
class Context
|
8
|
+
class << self
|
9
|
+
attr_accessor :last
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :config, :gem, :system
|
13
|
+
|
14
|
+
COLORS = {
|
15
|
+
red: "\e[31m",
|
16
|
+
green: "\e[32m",
|
17
|
+
yellow: "\e[33m",
|
18
|
+
blue: "\e[34m",
|
19
|
+
gray: "\e[37m",
|
20
|
+
reset: "\e[0m"
|
21
|
+
}
|
22
|
+
|
23
|
+
def initialize(name = nil)
|
24
|
+
@config = Config.new
|
25
|
+
@gem = Gem.new(name || File.basename(Dir.pwd))
|
26
|
+
@system = System.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def announce(str)
|
30
|
+
puts colored(:green, with_spacing(str, true))
|
31
|
+
end
|
32
|
+
|
33
|
+
def info(str)
|
34
|
+
puts colored(:blue, with_spacing(str, true))
|
35
|
+
end
|
36
|
+
|
37
|
+
def notice(str)
|
38
|
+
puts colored(:gray, with_spacing(str, false))
|
39
|
+
end
|
40
|
+
|
41
|
+
def warn(str)
|
42
|
+
puts colored(:yellow, with_spacing(str, false))
|
43
|
+
end
|
44
|
+
|
45
|
+
def error(str)
|
46
|
+
puts colored(:red, with_spacing(str, true))
|
47
|
+
end
|
48
|
+
|
49
|
+
def abort(str)
|
50
|
+
error(str)
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def in_dirs(args, opts, &block)
|
55
|
+
Paths::ByNames.new(args, opts).in_dirs(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def in_gem_dirs(args, opts, &block)
|
59
|
+
Paths::ByGemspecs.new(args, opts).in_dirs(&block)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def colored(color, str)
|
65
|
+
[COLORS[color], str, COLORS[:reset]].join
|
66
|
+
end
|
67
|
+
|
68
|
+
def with_spacing(str, space)
|
69
|
+
space = false if self.class.last.nil?
|
70
|
+
str = "\n#{str}" if space && !self.class.last
|
71
|
+
self.class.last = space
|
72
|
+
str
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|