crackin 0.0.1.rc0

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.
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: []