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.
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,28 @@
1
+ require 'gem/release/context/gemspec'
2
+
3
+ module Gem
4
+ module Release
5
+ class Context
6
+ class Gem
7
+ attr_reader :name, :spec
8
+
9
+ def initialize(name)
10
+ @spec = Gemspec.new(name)
11
+ @name = name
12
+ end
13
+
14
+ def version
15
+ spec.version.to_s if spec
16
+ end
17
+
18
+ def filename
19
+ spec.gem_filename if spec
20
+ end
21
+
22
+ def spec_filename
23
+ spec.filename if name
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ module Gem
2
+ module Release
3
+ class Context
4
+ class Gemspec < Struct.new(:name)
5
+ attr_reader :filename
6
+
7
+ def initialize(*)
8
+ super
9
+ @filename = name && "#{name}.gemspec" || filenames.first
10
+ end
11
+
12
+ def gem_name
13
+ gemspec.name if gemspec
14
+ end
15
+
16
+ def version
17
+ gemspec.version.to_s if gemspec
18
+ end
19
+
20
+ def gem_filename
21
+ gemspec.file_name if gemspec
22
+ end
23
+
24
+ def exists?
25
+ filename && File.exists?(filename)
26
+ end
27
+
28
+ private
29
+
30
+ def gemspec
31
+ return @gemspec if instance_variable_defined?(:@gemspec)
32
+ @gemspec = exists? ? ::Gem::Specification.load(filename) : nil
33
+ end
34
+
35
+ def filenames
36
+ Dir['*.gemspec'].map { |path| File.basename(path) }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,87 @@
1
+ require 'pathname'
2
+
3
+ module Gem
4
+ module Release
5
+ class Context
6
+ class Paths < Struct.new(:names, :opts)
7
+ class Base < Struct.new(:names, :opts)
8
+ def in_dir(dir, &block)
9
+ dir == cwd ? yield : Dir.chdir(dir, &block)
10
+ end
11
+
12
+ def current
13
+ [[cwd, cwd.basename.to_s]]
14
+ end
15
+
16
+ def cwd
17
+ @cwd ||= Pathname.pwd
18
+ end
19
+ end
20
+
21
+ class ByNames < Base
22
+ def in_dirs(&block)
23
+ dirs.each do |dir, name|
24
+ dir.mkdir unless dir == cwd || dir.exist?
25
+ in_dir(dir) { yield name }
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def dirs
32
+ names.any? ? dirs_by_names : current
33
+ end
34
+
35
+ def dirs_by_names
36
+ names.map { |name| [Pathname.new(dir || name).expand_path, name] }
37
+ end
38
+
39
+ def dir
40
+ opts[:dir]
41
+ end
42
+ end
43
+
44
+ class ByGemspecs < Base
45
+ def in_dirs(&block)
46
+ dirs.each do |dir, name|
47
+ in_dir(dir) { yield name }
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def dirs
54
+ dirs = by_gemspecs if opts[:recurse]
55
+ dirs ||= by_names if names.any?
56
+ dirs ||= gemspec
57
+ dirs || by_gemspecs || current
58
+ end
59
+
60
+ def by_gemspecs
61
+ paths = gemspecs(true).map { |path| [path.dirname, name_for(path)] }
62
+ paths unless paths.empty?
63
+ end
64
+
65
+ def by_names
66
+ paths = names.map { |arg| by_gemspecs.detect { |_, name| name == arg } }.compact
67
+ paths unless paths.empty?
68
+ end
69
+
70
+ def gemspec
71
+ path = gemspecs.first
72
+ [[path.expand_path.dirname, name_for(path)]] if path
73
+ end
74
+
75
+ def name_for(path)
76
+ path.basename('.gemspec').to_s
77
+ end
78
+
79
+ def gemspecs(recurse = false)
80
+ pattern = recurse ? '**/*.gemspec' : '*.gemspec'
81
+ Pathname.glob(pattern).map(&:expand_path).sort
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,36 @@
1
+ module Gem
2
+ module Release
3
+ class Context
4
+ class System
5
+ def run(cmd)
6
+ system(cmd)
7
+ end
8
+
9
+ def gem_cmd(cmd, *args)
10
+ ::Gem::Commands.const_get("#{cmd.to_s.capitalize}Command").new.invoke(*args.flatten)
11
+ # TODO what's with the return value? maybe add our own abstraction that can check the result?
12
+ true
13
+ end
14
+
15
+ def git_remotes
16
+ `git remote`.split("\n")
17
+ end
18
+
19
+ def git_user_name
20
+ str = `git config --get user.name`.strip
21
+ str unless str.empty?
22
+ end
23
+
24
+ def git_user_email
25
+ str = `git config --get user.email`.strip
26
+ str unless str.empty?
27
+ end
28
+
29
+ def github_user_name
30
+ str = `git config --get github.user`.strip
31
+ str.empty? ? git_user_name : str
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,60 @@
1
+ require 'erb'
2
+ require 'ostruct'
3
+ require 'gem/release/helper/string'
4
+
5
+ module Gem
6
+ module Release
7
+ class Data < Struct.new(:system, :gem, :opts)
8
+ include Helper::String
9
+
10
+ def data
11
+ {
12
+ gem_name: gem_name,
13
+ gem_path: gem_name.gsub('-', '/'),
14
+ module_names: module_names,
15
+ author: user_name,
16
+ email: user_email,
17
+ homepage: homepage,
18
+ licenses: licenses,
19
+ summary: '[summary]',
20
+ description: '[description]',
21
+ files: files
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ def module_names
28
+ gem_name.split('-').map { |part| camelize(part) }
29
+ end
30
+
31
+ def gem_name
32
+ gem.name || raise('No gem_name given.')
33
+ end
34
+
35
+ def user_name
36
+ system.git_user_name || '[your name]'
37
+ end
38
+
39
+ def user_email
40
+ system.git_user_email || '[your email]'
41
+ end
42
+
43
+ def homepage
44
+ "https://github.com/#{user_name}/#{gem_name}"
45
+ end
46
+
47
+ def licenses
48
+ Array(license).join(',').split(',').map(&:upcase)
49
+ end
50
+
51
+ def license
52
+ opts[:license] if opts[:license]
53
+ end
54
+
55
+ def files
56
+ STRATEGIES[(opts[:strategy] || :glob).to_sym] || STRATEGIES[:glob]
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,61 @@
1
+ require 'gem/release/files/template/context'
2
+
3
+ module Gem
4
+ module Release
5
+ module Files
6
+ class Template
7
+ FILES = {
8
+ '.gitignore' => '.gitignore',
9
+ 'Gemfile' => 'Gemfile',
10
+ 'gemspec' => '%{gem_name}.gemspec',
11
+ 'license' => 'MIT-LICENSE.md',
12
+ 'main.rb' => 'lib/%{gem_path}.rb',
13
+ 'version.rb' => 'lib/%{gem_path}/version.rb'
14
+ }
15
+
16
+ attr_accessor :source, :target, :data
17
+
18
+ def initialize(source, target, data)
19
+ @source = source
20
+ @target = (FILES[target] || target) % data
21
+ @data = data
22
+ end
23
+
24
+ PATH = File.expand_path('../..', __FILE__)
25
+
26
+ def filename
27
+ File.basename(target)
28
+ end
29
+
30
+ def write
31
+ return false if exists?
32
+ FileUtils.mkdir_p(File.dirname(target))
33
+ File.write(target, render)
34
+ true
35
+ end
36
+
37
+ def exists?
38
+ File.exist?(target.to_s)
39
+ end
40
+
41
+ private
42
+
43
+ def render
44
+ template.result(binding)
45
+ end
46
+
47
+ def template
48
+ ERB.new(File.read(source))
49
+ end
50
+
51
+ def binding
52
+ context.instance_eval { binding }
53
+ end
54
+
55
+ def context
56
+ Context.new(data)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,30 @@
1
+ module Gem
2
+ module Release
3
+ module Files
4
+ class Template
5
+ class Context < OpenStruct
6
+ class Const < Struct.new(:type, :names)
7
+ def define(&block)
8
+ lines = build(names) { |name| "#{type} #{name}" }
9
+ lines << indent(block.call, names.size) if block
10
+ lines += build(names) { |name| 'end' }.reverse
11
+ lines.join("\n")
12
+ end
13
+
14
+ def build(names, &block)
15
+ names.map.with_index { |name, ix| indent(block.call(name), ix) }
16
+ end
17
+
18
+ def indent(str, level)
19
+ "#{' ' * level}#{str}"
20
+ end
21
+ end
22
+
23
+ def define(type, &block)
24
+ Const.new(type, module_names).define(&block)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,59 @@
1
+ module Gem
2
+ module Release
3
+ module Files
4
+ class Templates < Struct.new(:files, :groups, :data)
5
+ BUILTIN = [
6
+ ['./.gem-release/%s'],
7
+ ['~/.gem-release/%s'],
8
+ ['../../templates/', __FILE__],
9
+ ]
10
+
11
+ CUSTOM = [
12
+ ['./.gem-release/%s'],
13
+ ['~/.gem-release/%s'],
14
+ ['../../templates/%s', __FILE__],
15
+ ]
16
+
17
+ LICENSE = [
18
+ ['./.gem-release/licenses'],
19
+ ['~/.gem-release/licenses'],
20
+ ['../../templates/licenses', __FILE__],
21
+ ]
22
+
23
+ def self.license(name, data)
24
+ file = Templates.new(["#{name}{,.*}"], [], data).license
25
+ file.target = "LICENSE#{File.extname(file.target)}" if file
26
+ file
27
+ end
28
+
29
+ def [](filename)
30
+ all.detect { |file| file.filename == filename }
31
+ end
32
+
33
+ def all
34
+ all = builtin + custom
35
+ all.flatten.uniq(&:target)
36
+ end
37
+
38
+ def builtin
39
+ templates_for(BUILTIN, files)
40
+ end
41
+
42
+ def custom
43
+ templates_for(CUSTOM, '**/*')
44
+ end
45
+
46
+ def license
47
+ templates_for(LICENSE, files).first
48
+ end
49
+
50
+ def templates_for(sources, files)
51
+ all = Group.new(groups, data, sources, files).all
52
+ all.map { |source, target| Template.new(source, target, data) }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ require 'gem/release/files/templates/group'
@@ -0,0 +1,47 @@
1
+ module Gem
2
+ module Release
3
+ module Files
4
+ class Templates
5
+ class Group
6
+ attr_reader :groups, :data, :sources, :files
7
+
8
+ def initialize(groups, data, sources, files)
9
+ @groups = [:default] + Array(groups)
10
+ @data = data
11
+ @sources = sources
12
+ @files = Array(files)
13
+ end
14
+
15
+ def all
16
+ return [] unless paths.any?
17
+ all = Dir.glob(pattern, File::FNM_DOTMATCH)
18
+ all = all.select { |file| File.file?(file) }
19
+ all.map { |file| [file, relative(file)] }
20
+ end
21
+
22
+ private
23
+
24
+ def pattern
25
+ "{#{paths.join(',')}}/{#{files.join(',')}}"
26
+ end
27
+
28
+ def relative(file)
29
+ paths.inject(file) { |file, path| file.sub("#{path}/", '') }
30
+ end
31
+
32
+ def paths
33
+ @paths ||= groups.map do |group|
34
+ paths = paths_for(group).map { |path| File.expand_path(*path) }
35
+ paths.detect { |path| File.exists?(path) }
36
+ end.compact
37
+ end
38
+
39
+ def paths_for(group)
40
+ sources.map { |paths| paths.map { |path| path % group } }
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+