git-lead-time 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ccefd21676389ce1ced4444101580df84a07abee
4
+ data.tar.gz: 9bb2ce0498ad5a2f184af9a1da719a7129fca87e
5
+ SHA512:
6
+ metadata.gz: e63a9c45d4d1e96faeef0dc27c9916cfa8a47349aa0b0c8335ceb2013a67bf17f495a1ae288a7875b31fcadf68356b90120862cf4dace9e0a98b2def1d2f5083
7
+ data.tar.gz: 98a1a09d173806a421160d3a1c429d123bd2b3c23f71d0e32027c360612a41e88f535f2bcf9d91a7bda470912f72c277021b8cfe8e92c3d0ceee9173eb02e104
@@ -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
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ before_script:
5
+ - "git config --global user.email 'me@example.com'"
6
+ - "git config --global user.name 'John Doe'"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git-lead-time.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Aaron Jensen
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.
@@ -0,0 +1,32 @@
1
+ # git lead-time
2
+
3
+ Show the lead time of branches merged into the current branch. Currently an
4
+ early proof of concept.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'git-lead-time'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install git-lead-time
19
+
20
+ ## Usage
21
+
22
+ ```bash
23
+ $ git lead-time
24
+ ```
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it ( http://github.com/<my-github-username>/git-lead-time/fork )
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path('../../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'git_lead_time'
6
+ GitLeadTime.run
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git_lead_time/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git-lead-time"
8
+ spec.version = GitLeadTime::VERSION
9
+ spec.authors = ["Aaron Jensen"]
10
+ spec.email = ["aaronjensen@gmail.com"]
11
+ spec.summary = %q{Show the lead time of branches merged into the current branch.}
12
+ spec.description = %q{Show the lead time of branches merged into the current branch.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec", "~>3.0.0.beta2"
24
+ spec.add_development_dependency "chronic"
25
+ end
@@ -0,0 +1 @@
1
+ require_relative 'git_lead_time'
@@ -0,0 +1,7 @@
1
+ require_relative 'git_lead_time/lead_time_command'
2
+
3
+ module GitLeadTime
4
+ def self.run
5
+ puts LeadTimeCommand.new.run
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ require 'set'
2
+
3
+ module GitLeadTime
4
+ class FirstCommitFinder
5
+ attr_reader :target_refs
6
+ def initialize(merge_target)
7
+ @target_refs = Set.new(first_parents(merge_target))
8
+ end
9
+
10
+ def first_commit(ref)
11
+ first_commit = ref
12
+ first_parents(ref).each do |parent|
13
+ break if target_refs.include? parent
14
+ first_commit = parent
15
+ end
16
+
17
+ first_commit
18
+ end
19
+
20
+ private
21
+ def first_parents(ref)
22
+ return to_enum(__method__, ref) unless block_given?
23
+
24
+ `git rev-list --first-parent #{ref}`.each_line do |line|
25
+ yield line.strip
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,62 @@
1
+ require 'time'
2
+ require_relative 'first_commit_finder'
3
+
4
+ module GitLeadTime
5
+ class LeadTimeCommand
6
+ attr_reader :first_commit_finder
7
+ def initialize(ref="HEAD")
8
+ @first_commit_finder = FirstCommitFinder.new(ref)
9
+ end
10
+
11
+ def run
12
+ merges.map { |merge| format_merge(merge) }
13
+ end
14
+
15
+ def merges
16
+ `git rev-list --merges --first-parent HEAD | head -10`.lines.map(&:chomp)
17
+ end
18
+
19
+ def format_merge(merge)
20
+ Format.new(Merge.new(merge, first_commit_finder)).to_s
21
+ end
22
+
23
+ class Merge
24
+ attr_reader *%i[merge_commit first_commit message end_date start_date]
25
+
26
+ def initialize(sha, first_commit_finder)
27
+ first_sha = first_commit_finder.first_commit("#{sha}^2")
28
+ @merge_commit, @message, @end_date = status("%h\n%s\n%cd", sha)
29
+ @first_commit, @start_date = status("%h\n%cd", first_sha)
30
+ end
31
+
32
+ def status(format, ref)
33
+ `git show -s --format='#{format}' #{ref}`.lines.map(&:strip)
34
+ end
35
+
36
+ def lead_time
37
+ (Time.parse(end_date) - start_date) / 60 / 60 / 24
38
+ end
39
+
40
+ def start_date
41
+ Time.parse `git show -s --format=%cd #{first_commit}`
42
+ end
43
+ end
44
+
45
+ class Format
46
+ attr_reader :merge
47
+
48
+ def initialize(merge)
49
+ @merge = merge
50
+ end
51
+
52
+ def to_s
53
+ "#{format_lead_time(merge.lead_time)} #{merge.first_commit}..#{merge.merge_commit} #{merge.message}"
54
+ end
55
+
56
+ def format_lead_time(lead_time)
57
+ time = ("%5.1f" % lead_time)
58
+ "#{time} day#{"s" unless time == "1.0"}"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module GitLeadTime
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe "git lead-time", :git do
4
+ it "shows the lead time for each merge" do
5
+ git_commit "Initial commit", on("monday 9am")
6
+ git :checkout, "-b", "topic"
7
+ git_commit "Topic commit A", on("tuesday 9am")
8
+ first_commit = git_head(:abbreviated)
9
+ git_commit "Topic commit B", on("wednesday 9am")
10
+ git :checkout, "master"
11
+ merge_commit = git_merge "topic", on("thursday 9am")
12
+ # Example: [master 160a500] Merge branch 'topic'
13
+ sha, message = merge_commit.chomp.match(/^\[\S+ ([^\]]+)\] (.*)$/)[1,2]
14
+
15
+ git "log", "--graph"
16
+ output = git "lead-time"
17
+ expect(output.lines.map(&:chomp)).to eq [
18
+ " 2.0 days #{first_commit}..#{sha} #{message}"
19
+ ]
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'git_lead_time/first_commit_finder'
3
+
4
+ module GitLeadTime
5
+ describe FirstCommitFinder, :git do
6
+ it "finds the first commit of a new branch" do
7
+ git_commit "Initial commit"
8
+
9
+ git "checkout", "-b", "topic"
10
+ git_commit "Topic A"
11
+ first_commit = git_head
12
+ git_commit "Topic B"
13
+ git_commit "Topic C"
14
+
15
+ git "checkout", "master"
16
+ git_merge "topic"
17
+ git "branch", "-D", "topic"
18
+
19
+
20
+ finder = FirstCommitFinder.new("master")
21
+ expect(finder.first_commit("master^2")).to eq(first_commit)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,61 @@
1
+ Dir['./spec/support/**/*.rb'].map {|f| require f}
2
+ ENV["PATH"] = "#{File.expand_path("../../bin", __FILE__)}:#{ENV['PATH']}"
3
+
4
+ RSpec.configure do |config|
5
+ # These two settings work together to allow you to limit a spec run
6
+ # to individual examples or groups you care about by tagging them with
7
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
8
+ # get run.
9
+ config.filter_run :focus
10
+ config.run_all_when_everything_filtered = true
11
+
12
+ # Many RSpec users commonly either run the entire suite or an individual
13
+ # file, and it's useful to allow more verbose output when running an
14
+ # individual spec file.
15
+ if config.files_to_run.one?
16
+ # RSpec filters the backtrace by default so as not to be so noisy.
17
+ # This causes the full backtrace to be printed when running a single
18
+ # spec file (e.g. to troubleshoot a particular spec failure).
19
+ #config.full_backtrace = true
20
+
21
+ # Use the documentation formatter for detailed output,
22
+ # unless a formatter has already been configured
23
+ # (e.g. via a command-line flag).
24
+ config.formatter = 'doc' if config.formatters.none?
25
+ end
26
+
27
+ # Run specs in random order to surface order dependencies. If you find an
28
+ # order dependency and want to debug it, you can fix the order by providing
29
+ # the seed, which is printed after each run.
30
+ # --seed 1234
31
+ config.order = :random
32
+
33
+ # Seed global randomization in this process using the `--seed` CLI option.
34
+ # Setting this allows you to use `--seed` to deterministically reproduce
35
+ # test failures related to randomization by passing the same `--seed` value
36
+ # as the one that triggered the failure.
37
+ Kernel.srand config.seed
38
+
39
+ # rspec-expectations config goes here. You can use an alternate
40
+ # assertion/expectation library such as wrong or the stdlib/minitest
41
+ # assertions if you prefer.
42
+ config.expect_with :rspec do |expectations|
43
+ # Enable only the newer, non-monkey-patching expect syntax.
44
+ # For more details, see:
45
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
46
+ expectations.syntax = :expect
47
+ end
48
+
49
+ # rspec-mocks config goes here. You can use an alternate test double
50
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
51
+ config.mock_with :rspec do |mocks|
52
+ # Enable only the newer, non-monkey-patching expect syntax.
53
+ # For more details, see:
54
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
55
+ mocks.syntax = :expect
56
+
57
+ # Prevents you from mocking or stubbing a method that does not exist on
58
+ # a real object. This is generally recommended.
59
+ mocks.verify_partial_doubles = true
60
+ end
61
+ end
@@ -0,0 +1,72 @@
1
+ require 'tmpdir'
2
+ require 'chronic'
3
+
4
+ module Support
5
+ module Git
6
+ def git_commit(message = :default, date: :now)
7
+ @commit_counter ||= 0
8
+ @commit_counter += 1
9
+ args = []
10
+ case message
11
+ when :default
12
+ args += ["-m", "Commit ##{@commit_counter}"]
13
+ when :no_edit
14
+ args += ["--no-edit"]
15
+ else
16
+ args += ["-m", message]
17
+ end
18
+
19
+ unless date == :now
20
+ args += ["--date", date]
21
+ end
22
+
23
+ git :commit, "--allow-empty", *args, date: date
24
+ #git "rev-parse", "HEAD"
25
+ end
26
+
27
+ def git_merge(branch, date: :now)
28
+ git :merge, "--no-ff", "--no-commit", "topic", date: date
29
+ git_commit :no_edit, date: date
30
+ end
31
+
32
+ def git_head(abbreviated)
33
+ if abbreviated
34
+ git("show", "-s", "--format=%h").chomp
35
+ else
36
+ git("rev-parse", "HEAD").chomp
37
+ end
38
+ end
39
+
40
+ def git(*args, date: :now)
41
+ if date != :now
42
+ ENV["GIT_COMMITTER_DATE"] = date
43
+ end
44
+
45
+ output = `#{["git", *args.map(&:to_s)].shelljoin} 2>&1`
46
+ raise unless $?.success?
47
+ output
48
+ rescue
49
+ puts output
50
+ raise
51
+ ensure
52
+ ENV["GIT_COMMITTER_DATE"] = nil
53
+ end
54
+
55
+ def on(date)
56
+ { date: Chronic.parse(date, now: Time.local(2014, 2, 1)).strftime("%a, %b %d %k:%M %Y %z") }
57
+ end
58
+ end
59
+ end
60
+
61
+ RSpec.configure do |config|
62
+ config.around :each, :git do |example|
63
+ Dir.mktmpdir do |dir|
64
+ Dir.chdir(dir) do
65
+ git :init
66
+ example.run
67
+ end
68
+ end
69
+ end
70
+
71
+ config.include Support::Git, :git
72
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-lead-time
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Jensen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0.beta2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0.beta2
55
+ - !ruby/object:Gem::Dependency
56
+ name: chronic
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Show the lead time of branches merged into the current branch.
70
+ email:
71
+ - aaronjensen@gmail.com
72
+ executables:
73
+ - git-lead-time
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/git-lead-time
84
+ - git-lead-time.gemspec
85
+ - lib/git-lead-time.rb
86
+ - lib/git_lead_time.rb
87
+ - lib/git_lead_time/first_commit_finder.rb
88
+ - lib/git_lead_time/lead_time_command.rb
89
+ - lib/git_lead_time/version.rb
90
+ - spec/features/lead_time_spec.rb
91
+ - spec/lib/git_lead_time/first_commit_finder_spec.rb
92
+ - spec/spec_helper.rb
93
+ - spec/support/git.rb
94
+ homepage: ''
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.2
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Show the lead time of branches merged into the current branch.
118
+ test_files:
119
+ - spec/features/lead_time_spec.rb
120
+ - spec/lib/git_lead_time/first_commit_finder_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/support/git.rb