crackin 0.0.1.rc0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWNmZTcwNTc3MmY2Yjc2NWQ2NDU0YTdmMWRlOTY3NWVjODhlNmM2ZA==
5
+ data.tar.gz: !binary |-
6
+ OTBmMmFlMDBlMWIyYjczNDQ0OTJmZDVjNWI3NmRkMjBjN2UyZTk4Zg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NTRjYTI5MzAyZTRkMjlkZDkyZjY3ZWZjYjJjZTY4ZWVkMGQwYWU4MTZhZWU0
10
+ NTg5MzM1Yjk2MjVlMDMyNTAzOTQ1YWE5ZjI0Mzc2Y2IxZWVhZTE5MmM5NTEz
11
+ NWIzNTE0OTllNTRmMWIxYjI0YjZkZjdhMjcxNzI5YmM2ZDFhNjc=
12
+ data.tar.gz: !binary |-
13
+ NWUwNjYwYTU0NTkwNmUyNmZhNTk4NGIwZTIyMWM2M2ViNTViODkxYTFhNWMx
14
+ MjdjYWU5MzljZjIxNDhlYTY4MGE5M2E4Njg5NTViOWU5ZWQxY2M4ZmZkOTI3
15
+ MDBjY2Q4Nzk3MjMxNjYwNDBkODc1NDk5YWQ5ODM2NDhmYWEwMDE=
data/.crackin.yml ADDED
@@ -0,0 +1,14 @@
1
+ ---
2
+ crackin:
3
+ name: crackin
4
+ scm: git
5
+ changelog: CHANGELOG.md
6
+ branch:
7
+ production: master
8
+ development: develop
9
+ status:
10
+ verbose: true
11
+ version: lib/crackin/version.rb
12
+ build:
13
+ command: rake build
14
+ after: []
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-1.9.3-p448@crackin
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in crackin.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Shawn Catanzarite
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Crackin
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'crackin'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install crackin
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/crackin ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'clamp'
5
+ require 'crackin'
6
+
7
+ module Crackin
8
+ class Command < Clamp::Command
9
+ option %w{-c --config}, '[CONFIG]', 'configuration file', environment_variable: 'CRACKIN_CONFIG', default: './.crackin.yml' do |config|
10
+ Crackin::Config.load(config)
11
+ end
12
+ subcommand 'init', 'intialize a directory for use with crackin' do
13
+ def execute
14
+ data = {crackin: Crackin::Config.defaults}.deep_stringify_keys
15
+ File.open(".crackin.yml", "w+") {|f| f.write(data.to_yaml)}
16
+ end
17
+ end
18
+ subcommand 'status', 'show status information' do
19
+ def execute
20
+ puts Crackin::Status.new
21
+ end
22
+ end
23
+ subcommand 'release', 'commands for doing releases' do
24
+ option %w{-n --dryrun}, :flag, 'mock commands', default: false
25
+ subcommand 'major', 'major release' do
26
+ def execute
27
+ release_start(:major, dryrun?)
28
+ end
29
+ end
30
+ subcommand 'minor', 'minor release' do
31
+ def execute
32
+ release_start(:minor, dryrun?)
33
+ end
34
+ end
35
+ subcommand 'tiny', 'tiny release' do
36
+ def execute
37
+ release_start(:tiny, dryrun?)
38
+ end
39
+ end
40
+ subcommand 'rc', 'release candidate release' do
41
+ def execute
42
+ release_start(:rc, dryrun?)
43
+ end
44
+ end
45
+ subcommand 'beta', 'beta release' do
46
+ def execute
47
+ release_start(:beta, dryrun?)
48
+ end
49
+ end
50
+ subcommand 'alpha', 'alpha release' do
51
+ def execute
52
+ release_start(:alpha, dryrun?)
53
+ end
54
+ end
55
+ subcommand 'rollback', 'rollback release changes' do
56
+ def execute
57
+ release_rollback(dryrun?)
58
+ end
59
+ end
60
+ subcommand 'finish', 'complete release process' do
61
+ def execute
62
+ release_finish(dryrun?)
63
+ end
64
+ end
65
+ end
66
+
67
+ def state(wanted)
68
+ status = Crackin::Status.new
69
+ status.state == wanted
70
+ end
71
+ def release_start(type, real)
72
+ raise "cannot start release when you're not in state == development" unless state('development')
73
+ Crackin::Release.new(type).start(real: real)
74
+ end
75
+ def release_rollback(real)
76
+ raise "cannot rollback when you're not in state == releasing" unless state('releasing')
77
+ Crackin::Release.new(:none).rollback(real: real)
78
+ end
79
+ def release_finish(real)
80
+ raise "cannot finish when you're not in state == releasing" unless state('releasing')
81
+ Crackin::Release.new(:none).finish(real: real)
82
+ end
83
+ end
84
+ end
85
+
86
+ begin
87
+ Crackin::Command.run
88
+ rescue => e
89
+ puts "error: #{e.message}"
90
+ e.backtrace.each {|l| puts " #{l}"}
91
+ exit 1
92
+ end
data/crackin.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'crackin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "crackin"
8
+ spec.version = Crackin::Version::STRING
9
+ spec.authors = ["Shawn Catanzarite"]
10
+ spec.email = ["me@shawncatz.com"]
11
+ spec.description = %q{release the crackin - gem release management}
12
+ spec.summary = %q{release the crackin - gem release management}
13
+ spec.homepage = "http://github.com/shawncatz/crackin"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'git'
22
+ spec.add_dependency 'clamp'
23
+ spec.add_dependency 'activesupport'
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ end
@@ -0,0 +1,152 @@
1
+ module Crackin
2
+ class Changelog
3
+ def initialize(file, version, options={})
4
+ @options = {
5
+ first: false
6
+ }.merge(options)
7
+ @output = file
8
+ @version = version
9
+ @config = Crackin.config
10
+ @source = @config.source
11
+ @data = {}
12
+ end
13
+
14
+ def to_s
15
+ tags = order_tags([@version, source_tags, @data.keys].flatten.uniq).reverse
16
+ out = "### Changelog\n\n"
17
+ tags.each do |section|
18
+ lines = @data[section]
19
+ out += "##### #{section}:\n"
20
+ out += lines.join("\n") if lines
21
+ out += "\n\n"
22
+ end
23
+ out
24
+ end
25
+
26
+ def update
27
+ tags = ordered_tags
28
+ load
29
+ @data[@version] = between(tags.last, 'HEAD').uniq
30
+ end
31
+
32
+ def full
33
+ tags = ordered_tags
34
+ to = 'HEAD'
35
+ name = @version
36
+ tags.reverse_each do |from|
37
+ @data[name] = between(from, to).uniq
38
+ to = from
39
+ name = from
40
+ end
41
+ end
42
+
43
+ def save
44
+ File.open(@output, "w+") {|f| f.write(to_s)}
45
+ end
46
+
47
+ protected
48
+
49
+ def ordered_tags
50
+ order_tags(source_tags)
51
+ end
52
+
53
+ def order_tags(list)
54
+ ordered = list.sort_by { |e| tag_to_number(e) }
55
+ ordered #.reject { |e| (a, b, c, d) = e.split("."); !d.nil? }
56
+ end
57
+
58
+ def tag_to_number(tag)
59
+ (a, b, c, d) = tag.gsub(/^v/, "").split(".")
60
+ tags = {'rc' => 3, 'beta' => 2, 'alpha' => 1}
61
+ t = 4
62
+ n = 0
63
+ if d && d =~ /(\w+)(\d+)/
64
+ t = tags[$1]
65
+ n = $2
66
+ end
67
+ str = ("%03d%03d%03d%03d%03d" % [a, b, c, t, n])
68
+ number = str.to_i
69
+ #puts "## #{tag} => #{str} => #{number}"
70
+ number
71
+ end
72
+
73
+ def source_tags
74
+ @source.tags.all.map(&:name)
75
+ end
76
+
77
+ def load
78
+ return unless File.exists?(@output)
79
+ file = File.open(@output).read
80
+ section = nil
81
+ file.lines.each do |line|
82
+ next if line =~ /^$/
83
+ if line =~ /^#####\s+(.*):/
84
+ section = $1
85
+ next
86
+ end
87
+ if section
88
+ @data[section] ||= []
89
+ @data[section] << line.chomp
90
+ end
91
+ end
92
+ end
93
+
94
+ def between(from, to)
95
+ log = @source.between(from, to)
96
+ out = []
97
+ log.each do |c|
98
+ m = message(c.message)
99
+ out << m if m
100
+ end
101
+ out
102
+ end
103
+
104
+ def message(m)
105
+ out = nil
106
+ if m !~ /^(merge|v|version|changelog|crackin)/i
107
+ out = "* #{m}"
108
+ end
109
+ out
110
+ end
111
+
112
+ #def changelog(last=nil, single=false)
113
+ # command="git --no-pager log --format='%an::::%h::::%s'"
114
+ #
115
+ # list = `git tag`
116
+ #
117
+ # puts "# Changelog"
118
+ # puts
119
+ #
120
+ # ordered = list.lines.sort_by { |e| (a, b, c) = e.gsub(/^v/, "").split("."); "%3d%3d%3d" % [a, b, c] }
121
+ #
122
+ # ordered.reject { |e| (a, b, c, d) = e.split("."); !d.nil? }.reverse_each do |t|
123
+ # tag = t.chomp
124
+ #
125
+ # if last
126
+ # check = {}
127
+ # out = []
128
+ # log = `#{command} #{last}...#{tag}`
129
+ # log.lines.each do |line|
130
+ # (who, hash, msg) = line.split('::::')
131
+ # unless check[msg]
132
+ # unless msg =~ /^Merge branch/ || msg =~ /CHANGELOG/ || msg =~ /^(v|version|changes for|preparing|ready for release|ready to release|bump version)*\s*(v|version)*\d+\.\d+\.\d+/
133
+ # msg.gsub(" *", "\n*").gsub(/^\*\*/, " *").lines.each do |l|
134
+ # line = l =~ /^(\s+)*\*/ ? l : "* #{l}"
135
+ # out << line
136
+ # end
137
+ # check[msg] = hash
138
+ # end
139
+ # end
140
+ # end
141
+ # puts "## #{last}:"
142
+ # out.each { |e| puts e }
143
+ # #puts log
144
+ # puts
145
+ # end
146
+ #
147
+ # last = tag
148
+ # exit if single
149
+ # end
150
+ #end
151
+ end
152
+ end
@@ -0,0 +1,63 @@
1
+ require 'yaml'
2
+ require 'active_support/all'
3
+
4
+ module Crackin
5
+ class Config
6
+ attr_reader :source
7
+
8
+ def initialize(file="./.crackin.yml")
9
+ yaml = YAML.load_file(file)
10
+ @config = self.class.defaults.deep_merge(yaml['crackin']||{})
11
+ @source = Crackin::Scm.open(@config)
12
+ end
13
+
14
+ def [](key)
15
+ @config[key]
16
+ end
17
+
18
+ class << self
19
+ def load(file="./.crackin.yml")
20
+ @config = Crackin::Config.new(file)
21
+ end
22
+
23
+ def instance
24
+ @config || load
25
+ end
26
+
27
+ def defaults
28
+ {
29
+ name: '<app>',
30
+ scm: 'git',
31
+ changelog: 'CHANGELOG.md',
32
+ branch: {
33
+ production: 'master',
34
+ development: 'develop'
35
+ },
36
+ status: {
37
+ verbose: true
38
+ },
39
+ version: 'lib/<app>/version.rb',
40
+ build: {
41
+ command: 'rake build', # gem build :name.gemspec && mkdir -p pkg && mv :name.gem pkg
42
+ after: []
43
+ }
44
+
45
+ }.deep_stringify_keys
46
+ end
47
+ end
48
+ end
49
+
50
+ class << self
51
+ def config
52
+ Crackin::Config.instance
53
+ end
54
+
55
+ def version
56
+ Crackin::VersionFile.new(config['version'])
57
+ end
58
+
59
+ def source
60
+ config.source
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ class Hash
2
+ def deep_transform_keys(&block)
3
+ result = {}
4
+ each do |key, value|
5
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
6
+ end
7
+ result
8
+ end unless Hash.respond_to?(:deep_transform_keys)
9
+
10
+ def deep_stringify_keys
11
+ deep_transform_keys{ |key| key.to_s }
12
+ end unless Hash.respond_to?(:deep_stringify_keys)
13
+ end
@@ -0,0 +1,13 @@
1
+ module Git
2
+ class Base
3
+ def tag_delete(tag_name)
4
+ tag = tag(tag_name)
5
+ self.lib.tag_delete(tag_name)
6
+ tag
7
+ end
8
+
9
+ def branch_current
10
+ self.lib.branch_current
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module Git
2
+ class Lib
3
+ def tag_delete(tag_name)
4
+ command('tag', ['-d', tag_name])
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,187 @@
1
+ module Crackin
2
+ class Release
3
+ def initialize(type)
4
+ @config = Crackin.config
5
+ @source = @config.source
6
+ @current = @source.current_branch
7
+ @type = type
8
+ @version = Crackin::VersionFile.new(@config['version'])
9
+ raise "unknown version type: #{type}" unless @version.respond_to?(type.to_sym)
10
+ @version.send(type.to_sym)
11
+ end
12
+
13
+ def start(options={})
14
+ o = {
15
+ real: true
16
+ }.merge(options)
17
+ # make sure no pending changes
18
+ raise "there are pending changes" if o[:real] && @source.pending?
19
+
20
+ puts "release: #{@version}"
21
+ run(start_actions)
22
+ end
23
+
24
+ def finish(options={})
25
+ o = {
26
+ real: true
27
+ }.merge(options)
28
+ run(finish_actions)
29
+ end
30
+
31
+ def rollback(options={})
32
+ puts "rolling back: #{@version}"
33
+ undo(start_actions)
34
+ end
35
+
36
+ protected
37
+
38
+ def run(actions)
39
+ begin
40
+ actions.each do |action|
41
+ puts ".. #{action[:name]}"
42
+ if action.keys.include?(:if) && !action[:if]
43
+ raise action[:failed] || "if statement evaluated to false"
44
+ end
45
+ action[:do].call
46
+ action[:success] = true
47
+ end
48
+ rescue => e
49
+ puts "** action failed: #{e.message}"
50
+ puts "## rolling back"
51
+ undo(actions)
52
+ end
53
+ end
54
+
55
+ def undo(actions)
56
+ actions.reverse.each do |action|
57
+ puts ".. undo: #{action[:name]}"
58
+ begin
59
+ action[:undo].call if action[:undo] #&& (action.keys.include?(:success) && action[:success])
60
+ rescue => e
61
+ puts "** failed: #{e.message}"
62
+ end
63
+ end
64
+ end
65
+
66
+ def start_actions
67
+ actions = []
68
+ # change branch
69
+ actions << {
70
+ name: "change to production branch",
71
+ do: -> { @source.change_branch(@config['branch']['production']) },
72
+ undo: -> { @source.change_branch(@config['branch']['development']) },
73
+ if: @current == @config['branch']['development']
74
+ }
75
+ # create release branch
76
+ actions << {
77
+ name: "create release branch",
78
+ do: -> { @source.create_branch("crackin_#{@version.name}") },
79
+ undo: -> { @source.delete_branch("crackin_#{@version.name}") },
80
+ }
81
+ # merge from develop
82
+ actions << {
83
+ name: "merge from develop",
84
+ do: -> { @source.merge_from(@config['branch']['development']) },
85
+ undo: -> { @source.uncommit },
86
+ }
87
+ # change version file
88
+ actions << {
89
+ name: "update version file",
90
+ do: -> { @version.save },
91
+ undo: -> { @source.reset },
92
+ }
93
+ # changelog
94
+ actions << {
95
+ name: "update changelog",
96
+ do: -> {
97
+ changelog = Crackin::Changelog.new(@config['changelog'], @version.name)
98
+ changelog.update
99
+ changelog.save
100
+ },
101
+ undo: -> { @source.reset },
102
+ }
103
+ actions
104
+ end
105
+
106
+ def finish_actions
107
+ actions = []
108
+ unless File.exist?(File.expand_path('~/.gem/credentials'))
109
+ puts "gem credentials are not saved, you must run 'gem push pkg/#{@config['name']}-#{@version.name}.gem' to set them"
110
+ return
111
+ end
112
+ # commit
113
+ actions << {
114
+ name: "commit version and changelog",
115
+ do: -> { @source.commit(@version.name) },
116
+ undo: -> { @source.uncommit },
117
+ }
118
+ # change branch
119
+ actions << {
120
+ name: "change to production branch",
121
+ do: -> { @source.change_branch(@config['branch']['production']) },
122
+ undo: -> { @source.change_branch(@config['branch']['development']) },
123
+ #if: -> { @current != @config['branch']['production'] }
124
+ }
125
+ # merge from crackin branch
126
+ actions << {
127
+ name: "merge from crackin release branch",
128
+ do: -> { @source.merge_from(@current) },
129
+ undo: -> { @source.uncommit },
130
+ }
131
+ # tag
132
+ actions << {
133
+ name: "create tag",
134
+ do: -> { @source.tags.create(@version.name) },
135
+ undo: -> { @source.tags.delete(@version.name) },
136
+ }
137
+ # build
138
+ actions << {
139
+ name: "run build",
140
+ do: -> { raise "system command failed" unless system(@config['build']['command']) },
141
+ }
142
+ # push
143
+ actions << {
144
+ name: "source push",
145
+ do: -> { @source.push },
146
+ }
147
+ # push tags
148
+ actions << {
149
+ name: "tags push",
150
+ do: -> { @source.push_tags('origin', @config['branch']['production']) },
151
+ }
152
+ # gem push
153
+ actions << {
154
+ name: "gem push 'pkg/#{@config['name']}-#{@version.number}.gem'",
155
+ do: -> {
156
+ raise "system command failed" unless system("gem push pkg/#{@config['name']}-#{@version.number}.gem")
157
+ },
158
+ undo: -> {
159
+ puts "** You will need to manually yank the gem that was pushed."
160
+ }
161
+ }
162
+ # change branch
163
+ actions << {
164
+ name: "change to development branch",
165
+ do: -> { @source.change_branch(@config['branch']['development']) },
166
+ undo: -> { @source.change_branch(@config['branch']['production']) },
167
+ }
168
+ # merge from production
169
+ actions << {
170
+ name: "merge from production",
171
+ do: -> { @source.merge_from(@config['branch']['production']) },
172
+ undo: -> { @source.uncommit },
173
+ }
174
+ # delete release branch
175
+ actions << {
176
+ name: "delete release branch",
177
+ do: -> { @source.delete_branch("crackin_#{@version.name}") },
178
+ }
179
+ # push
180
+ actions << {
181
+ name: "source push",
182
+ do: -> { @source.push },
183
+ }
184
+ actions
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,111 @@
1
+ require 'git'
2
+ require 'shellwords'
3
+
4
+ module Crackin
5
+ module Scm
6
+ class Git < Base
7
+ attr_reader :git
8
+ def initialize(config={})
9
+ super
10
+ #@git = ::Git.open(@options[:working], log: Logger.new(STDOUT))
11
+ @git = ::Git.open(@options[:working])
12
+ end
13
+
14
+ def log
15
+ @git.log
16
+ end
17
+
18
+ def between(from, to)
19
+ @git.log.between(from, to)
20
+ end
21
+
22
+ def tags
23
+ Tags.new(@git)
24
+ end
25
+
26
+ def commit(message)
27
+ @git.commit_all(message)
28
+ end
29
+
30
+ def uncommit
31
+ @git.reset_hard('HEAD^')
32
+ end
33
+
34
+ def reset
35
+ @git.checkout_file('--', '.')
36
+ @git.clean(d: true, force: true)
37
+ #pending.keys.each do |p|
38
+ # puts "pending: #{p}"
39
+ # @git.checkout_file('--', p)
40
+ #end
41
+ end
42
+
43
+ def merge_from(from)
44
+ @git.branch(from).merge
45
+ end
46
+
47
+ def current_branch
48
+ @git.branch_current
49
+ end
50
+
51
+ def change_branch(to)
52
+ @git.checkout(to)
53
+ end
54
+
55
+ def create_branch(name)
56
+ branch = @git.branch(Shellwords.escape(name))
57
+ branch.create
58
+ branch.checkout
59
+ end
60
+
61
+ def delete_branch(name)
62
+ @git.checkout
63
+ @git.branch(Shellwords.escape(name)).delete
64
+ end
65
+
66
+ def push
67
+ @git.push
68
+ end
69
+
70
+ def push_tags(remote=@git.remote, branch=current_branch)
71
+ @git.push(remote, branch, true)
72
+ end
73
+
74
+ def pending
75
+ s = @git.status
76
+ d = {}
77
+ d.merge! s.changed
78
+ d.merge! s.added
79
+ d.merge! s.deleted
80
+ d.merge! s.untracked
81
+ d
82
+ end
83
+
84
+ def pending?
85
+ pending.count > 0
86
+ end
87
+ end
88
+
89
+ class Tags < Git
90
+ def initialize(git)
91
+ @git = git
92
+ end
93
+
94
+ def find(name)
95
+ @git.tag(name)
96
+ end
97
+
98
+ def create(name)
99
+ @git.add_tag(name)
100
+ end
101
+
102
+ def all
103
+ @git.tags
104
+ end
105
+
106
+ def destroy(name)
107
+ @git.tag_delete(name)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,45 @@
1
+ module Crackin
2
+ module Scm
3
+ class Base
4
+ def initialize(config={})
5
+ @options = {
6
+ production: 'master',
7
+ working: File.expand_path('.')
8
+ }.merge(config)
9
+ end
10
+
11
+ def commit(message)
12
+ raise "not implemented"
13
+ end
14
+
15
+ def change_branch
16
+ raise "not implemented"
17
+ end
18
+
19
+ def push
20
+ raise "not implemented"
21
+ end
22
+
23
+ def tag
24
+ raise "not implemented"
25
+ end
26
+
27
+ def push_tags
28
+ raise "not implemented"
29
+ end
30
+ end
31
+
32
+ class << self
33
+ def open(options)
34
+ name = options['scm'] || 'git'
35
+ klass = "Crackin::Scm::#{name.capitalize}".constantize
36
+ #puts "loading: #{klass}"
37
+ klass.new(options)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ Dir["#{File.dirname(__FILE__)}/scm/*.rb"].each do |file|
44
+ require "#{file.gsub(/\.rb/, '')}"
45
+ end
@@ -0,0 +1,144 @@
1
+ module Crackin
2
+ class Status
3
+ attr_reader :state
4
+
5
+ def initialize
6
+ @config = Crackin.config
7
+ @source = @config.source
8
+ @verbose = @config['status']['verbose']
9
+ @version = Crackin::VersionFile.new(@config['version'])
10
+ @notices = []
11
+
12
+ process
13
+ end
14
+
15
+ def process
16
+ if (@source.current_branch =~ /^crackin_/) == 0
17
+ # we're releasing
18
+ @state = 'releasing'
19
+ @notices << notice_releasing
20
+ @notices << notice_releasing_pending if @source.pending
21
+ @notices << notice_releasing_finish
22
+ elsif @source.current_branch == @config['branch']['development']
23
+ @state = 'development'
24
+ @notices << notice_development
25
+ elsif @source.current_branch == @config['branch']['production']
26
+ @state = 'production'
27
+ @notices << notice_production
28
+ else
29
+ @state = 'unknown'
30
+ @notices << notice_unknown
31
+ end
32
+ end
33
+
34
+ def releasing?
35
+ @state == 'releasing'
36
+ end
37
+
38
+ def production?
39
+ @state == 'production'
40
+ end
41
+
42
+ def development?
43
+ @state == 'development'
44
+ end
45
+
46
+ def unknown?
47
+ @state == 'unknown'
48
+ end
49
+
50
+ def status_line
51
+ "crackin # '#{@version}' # on branch: '#{@source.current_branch}' ('#{@state}') # pending changes: '#{@source.pending?}'"
52
+ end
53
+
54
+ def to_s
55
+ out = []
56
+ out += @notices if @verbose
57
+ out << status_line
58
+ out.join("\n")
59
+ end
60
+
61
+ protected
62
+
63
+ def notice_releasing
64
+ <<-RELEASING
65
+ You are in the midst of a release.
66
+ RELEASING
67
+ end
68
+
69
+ def notice_releasing_pending
70
+ <<-PENDING
71
+ There are pending changes.
72
+ Most likely, these are the changes made for you by Crackin.
73
+ The changes include updating your version file and change log.
74
+ Verify the changes and add any additional comments to the change log.
75
+ PENDING
76
+ end
77
+
78
+ def notice_releasing_finish
79
+ <<-FINISH
80
+ To continue run the following command:
81
+ crackin release finish
82
+
83
+ To abort - if you've changed your mind - run the following command:
84
+ crackin release rollback
85
+ FINISH
86
+ end
87
+
88
+ def notice_development
89
+ <<-DEV
90
+ You are ready for development. Make changes to the develop branch, or merge
91
+ features from feature branches.
92
+ Commit and push your changes.
93
+
94
+ When you wish to start a release, run the following command:
95
+ crackin release <type>
96
+
97
+ Crackin uses semantic versioning, for more information see: http://semver.org
98
+ <type> can be one of the following:
99
+
100
+ crackin release major # => release #{@version.dup.major}
101
+ crackin release minor # => release #{@version.dup.minor}
102
+ crackin release tiny # => release #{@version.dup.tiny}
103
+ crackin release rc # => release #{@version.dup.rc} # tag type
104
+ crackin release beta # => release #{@version.dup.beta} # tag type
105
+ crackin release alpha # => release #{@version.dup.alpha} # tag type
106
+
107
+ subsequent tag type releases increment the tag number rc1, beta1, alpha1.
108
+ you can release a main type release which will clear the tag.
109
+ An example timeline of releases:
110
+
111
+ start v0.4.0
112
+ alpha release v0.4.1.alpha0
113
+ alpha release v0.4.1.alpha1
114
+ beta release v0.4.1.beta0
115
+ rc release v0.4.1.rc0
116
+ rc release v0.4.1.rc1
117
+ tiny release v0.4.1
118
+ DEV
119
+ end
120
+
121
+ def notice_production
122
+ <<-PRODUCTION
123
+ You are on the production branch. Normal work will happen on development branches.
124
+ For now, Crackin does not support any other process than the default:
125
+ 1. make changes to development branch, or merge changes there from feature branches.
126
+ 2. crackin release <type> - merge development and production, update version and change log.
127
+
128
+ *** HOT FIX RELEASES ARE NOT YET SUPPORTED ***
129
+ PRODUCTION
130
+ end
131
+
132
+ def notice_unknown
133
+ <<-UNKNOWN
134
+ You are in an unknown state. Normally this happens for one of two reasons:
135
+
136
+ 1. There is a problem with your configuration.
137
+ Make sure that you have the branch values configured correctly
138
+ 2. You are doing feature development on a feature branch.
139
+ This is ok, you just need to merge your changes to your development branch
140
+ Then you can use crackin to do releases.
141
+ UNKNOWN
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,10 @@
1
+ module Crackin
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+ TAG = 'rc0'
7
+ LIST = [MAJOR, MINOR, TINY, TAG]
8
+ STRING = LIST.compact.join(".")
9
+ end
10
+ end
@@ -0,0 +1,100 @@
1
+ module Crackin
2
+ class VersionFile
3
+ def initialize(path)
4
+ @path = path
5
+ load
6
+ end
7
+
8
+ def load
9
+ File.read(@path).lines.each do |line|
10
+ @major = $1.to_i if line =~ /MAJOR\s+=\s+(\d+)/
11
+ @minor = $1.to_i if line =~ /MINOR\s+=\s+(\d+)/
12
+ @tiny = $1.to_i if line =~ /TINY\s+=\s+(\d+)/
13
+ if line =~ /TAG\s+=\s+(.*)/
14
+ @tag = $1
15
+ @tag.gsub!(/['"]/, '')
16
+ @tag = nil if @tag == 'nil'
17
+ end
18
+ end
19
+ end
20
+
21
+ def save
22
+ out = []
23
+ tag = @tag ? "'#{@tag}'" : "nil"
24
+ File.open(@path).lines.each do |line|; line.chomp!
25
+ line.gsub!(/(\s+)MAJOR\s+=\s+\d+/, "\\1MAJOR = #{@major}")
26
+ line.gsub!(/(\s+)MINOR\s+=\s+\d+/, "\\1MINOR = #{@minor}")
27
+ line.gsub!(/(\s+)TINY\s+=\s+\d+/, "\\1TINY = #{@tiny}")
28
+ line.gsub!(/(\s+)TAG\s+=\s+(nil|['"].*['"])/, "\\1TAG = #{tag}")
29
+ out << line
30
+ end
31
+ File.open(@path, "w+") {|f| f.write(out.join("\n"))}
32
+ end
33
+
34
+ def name
35
+ "v#{number}"
36
+ end
37
+
38
+ def to_s
39
+ name
40
+ end
41
+
42
+ def to_a
43
+ [@major, @minor, @tiny, @tag].compact
44
+ end
45
+
46
+ def number
47
+ to_a.join('.')
48
+ end
49
+
50
+ def major
51
+ @major += 1
52
+ @minor = 0
53
+ @tiny = 0
54
+ @tag = nil
55
+ name
56
+ end
57
+
58
+ def minor
59
+ @minor += 1
60
+ @tiny = 0
61
+ @tag = nil
62
+ name
63
+ end
64
+
65
+ def tiny
66
+ @tiny += 1 unless @tag
67
+ @tag = nil
68
+ name
69
+ end
70
+
71
+ def rc
72
+ tag('rc')
73
+ name
74
+ end
75
+
76
+ def beta
77
+ tag('beta')
78
+ name
79
+ end
80
+
81
+ def alpha
82
+ tag('alpha')
83
+ name
84
+ end
85
+
86
+ def tag(type)
87
+ if @tag =~ /#{type}(\d+)/
88
+ num = $1.to_i + 1
89
+ @tag = "#{type}#{num}"
90
+ else
91
+ @tiny += 1
92
+ @tag = "#{type}0"
93
+ end
94
+ end
95
+
96
+ def none
97
+
98
+ end
99
+ end
100
+ end
data/lib/crackin.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'crackin/version'
2
+ require 'crackin/scm'
3
+ require 'crackin/config'
4
+ require 'crackin/status'
5
+ require 'crackin/version_file'
6
+ require 'crackin/changelog'
7
+ require 'crackin/release'
8
+
9
+ require 'crackin/ext/git/base'
10
+ require 'crackin/ext/git/lib'
11
+ require 'crackin/ext/core/hash'
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crackin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.rc0
5
+ platform: ruby
6
+ authors:
7
+ - Shawn Catanzarite
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: git
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: clamp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: release the crackin - gem release management
84
+ email:
85
+ - me@shawncatz.com
86
+ executables:
87
+ - crackin
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .crackin.yml
92
+ - .gitignore
93
+ - .ruby-version
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - bin/crackin
99
+ - crackin.gemspec
100
+ - lib/crackin.rb
101
+ - lib/crackin/changelog.rb
102
+ - lib/crackin/config.rb
103
+ - lib/crackin/ext/core/hash.rb
104
+ - lib/crackin/ext/git/base.rb
105
+ - lib/crackin/ext/git/lib.rb
106
+ - lib/crackin/release.rb
107
+ - lib/crackin/scm.rb
108
+ - lib/crackin/scm/git.rb
109
+ - lib/crackin/status.rb
110
+ - lib/crackin/version.rb
111
+ - lib/crackin/version_file.rb
112
+ homepage: http://github.com/shawncatz/crackin
113
+ licenses:
114
+ - MIT
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ! '>'
128
+ - !ruby/object:Gem::Version
129
+ version: 1.3.1
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.1.10
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: release the crackin - gem release management
136
+ test_files: []