gem-release 1.0.0 → 2.0.0.dev.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +72 -0
  4. data/{lib/gem_release/templates/LICENSE → MIT-LICENSE.md} +3 -2
  5. data/README.md +646 -0
  6. data/README.md.erb +159 -0
  7. data/TODO.txt +194 -0
  8. data/lib/gem/release.rb +13 -0
  9. data/lib/gem/release/cmds.rb +16 -0
  10. data/lib/gem/release/cmds/base.rb +101 -0
  11. data/lib/gem/release/cmds/bootstrap.rb +222 -0
  12. data/lib/gem/release/cmds/bump.rb +165 -0
  13. data/lib/gem/release/cmds/gemspec.rb +85 -0
  14. data/lib/gem/release/cmds/release.rb +100 -0
  15. data/lib/gem/release/cmds/runner.rb +52 -0
  16. data/lib/gem/release/cmds/tag.rb +93 -0
  17. data/lib/gem/release/config.rb +42 -0
  18. data/lib/gem/release/config/env.rb +49 -0
  19. data/lib/gem/release/config/files.rb +35 -0
  20. data/lib/gem/release/context.rb +76 -0
  21. data/lib/gem/release/context/gem.rb +28 -0
  22. data/lib/gem/release/context/gemspec.rb +41 -0
  23. data/lib/gem/release/context/paths.rb +87 -0
  24. data/lib/gem/release/context/system.rb +36 -0
  25. data/lib/gem/release/data.rb +60 -0
  26. data/lib/gem/release/files/template.rb +61 -0
  27. data/lib/gem/release/files/template/context.rb +30 -0
  28. data/lib/gem/release/files/templates.rb +59 -0
  29. data/lib/gem/release/files/templates/group.rb +47 -0
  30. data/lib/gem/release/files/version.rb +68 -0
  31. data/lib/gem/release/helper.rb +45 -0
  32. data/lib/gem/release/helper/hash.rb +35 -0
  33. data/lib/gem/release/helper/string.rb +43 -0
  34. data/lib/gem/release/support/gem_command.rb +67 -0
  35. data/lib/gem/release/support/registry.rb +59 -0
  36. data/lib/gem/release/templates/.gitignore +8 -0
  37. data/lib/gem/release/templates/Gemfile +3 -0
  38. data/lib/gem/release/templates/gemspec +19 -0
  39. data/lib/gem/release/templates/licenses/mit.md +21 -0
  40. data/lib/gem/release/templates/licenses/mpl-2.md +373 -0
  41. data/lib/gem/release/templates/main.rb +1 -0
  42. data/lib/gem/release/templates/rspec/.rspec +3 -0
  43. data/lib/gem/release/templates/rspec/spec/spec_helper.rb +4 -0
  44. data/lib/gem/release/templates/travis/.travis.yml +1 -0
  45. data/lib/gem/release/templates/version.rb +1 -0
  46. data/lib/gem/release/version.rb +5 -0
  47. data/lib/gem/release/version/number.rb +102 -0
  48. data/lib/rubygems/commands/bootstrap_command.rb +4 -93
  49. data/lib/rubygems/commands/bump_command.rb +4 -110
  50. data/lib/rubygems/commands/gemspec_command.rb +5 -29
  51. data/lib/rubygems/commands/release_command.rb +4 -70
  52. data/lib/rubygems/commands/tag_command.rb +5 -46
  53. data/lib/rubygems_plugin.rb +8 -2
  54. metadata +56 -83
  55. data/lib/core_ext/hash/symbolize_keys.rb +0 -13
  56. data/lib/core_ext/kernel/silence.rb +0 -18
  57. data/lib/core_ext/string/camelize.rb +0 -5
  58. data/lib/gem_release.rb +0 -10
  59. data/lib/gem_release/command_options.rb +0 -31
  60. data/lib/gem_release/configuration.rb +0 -33
  61. data/lib/gem_release/gemspec_template.rb +0 -35
  62. data/lib/gem_release/helpers.rb +0 -104
  63. data/lib/gem_release/template.rb +0 -52
  64. data/lib/gem_release/templates/Gemfile +0 -3
  65. data/lib/gem_release/templates/README.md +0 -1
  66. data/lib/gem_release/templates/Rakefile +0 -10
  67. data/lib/gem_release/templates/gemspec +0 -18
  68. data/lib/gem_release/templates/gitignore +0 -25
  69. data/lib/gem_release/templates/test/test_helper.rb +0 -2
  70. data/lib/gem_release/templates/version.rb +0 -12
  71. data/lib/gem_release/version.rb +0 -3
  72. data/lib/gem_release/version_file.rb +0 -115
  73. 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