ballantine 0.1.4.pre.beta2 → 0.1.4.pre.beta3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 205e73804edf1a3ea9c16ddabb4dc3f5d1cc916300ff6f59576112153d8fadaa
4
- data.tar.gz: 3a742736e8db01a38761b0a395a94e7e16083edd35ff8cf460c77e4db0f797d5
3
+ metadata.gz: faa1e978d804f0d6db7c1c8b2d0d46a1fee27cd0a1f11c811b34f700fa99ac4d
4
+ data.tar.gz: 17a176cabd94e64d662bde533f605b6d36ebc19f301f6f77df3afc7870fdfedb
5
5
  SHA512:
6
- metadata.gz: 41654e7d79f79ca6a0c5a556e567ec40f64f343797b92c748c6930d012c6cf49c9674878aa81ad9e7d50f42f8740208a0003f7bf9cde5e11bc674f0f8e8d0b5a
7
- data.tar.gz: 214c98d8b880faf7b68aeefa65a5670c688186d2b3e2f3098e2c3ed42cd80f221282ce441de10b6ea12e2569ec977f4062954100206fedcf0f5eae509ca70a26
6
+ metadata.gz: 014f30ad7a7764ef9d2d8619a62c541de3e23115e9d9eddebf16da3d1e6f958fc5d2567f57d3072907f8df1d398ca9ff8e8f785675095ad95e8adabfa76e0080
7
+ data.tar.gz: eed48b827efdbab0ff935444936431ac08a8ef97b15a9291679ec45f64ea9b56a295ad4ae40049749d516d385e7daaad18017449638af38d7c0579cf2be155ff
@@ -2,16 +2,22 @@
2
2
 
3
3
  module Ballantine
4
4
  class Author
5
+ include Printable
6
+
5
7
  attr_reader :name, :commits_hash
6
8
 
7
9
  class << self
8
10
  # @param [String] name
9
- # @return [Author] author
10
- def find_or_create_by(name:)
11
+ # @return [Author, NilClass]
12
+ def find(name:)
11
13
  @_collections = {} unless defined?(@_collections)
12
- return @_collections[name] unless @_collections[name].nil?
14
+ @_collections[name]
15
+ end
13
16
 
14
- @_collections[name] = new(name:)
17
+ # @param [String] name
18
+ # @return [Author]
19
+ def find_or_create_by(name:)
20
+ find(name:) || @_collections[name] = new(name:)
15
21
  end
16
22
 
17
23
  # @return [Array<Author>] authors
@@ -33,8 +39,10 @@ module Ballantine
33
39
  puts "\n" + "@#{name}".green
34
40
  commits_hash.each do |repo_name, commits|
35
41
  count, word = retrieve_count_and_word(commits)
36
- puts " > #{repo_name.blue}: #{count} new #{word}\n"
37
- puts commits.map(&:message)
42
+ puts " > #{repo_name.blue}: #{count} new #{word}"
43
+ commits.each do |commit|
44
+ puts_r " - #{commit.hash.yellow} #{commit.subject}", commit.url.gray
45
+ end
38
46
  end
39
47
 
40
48
  true
@@ -42,11 +50,12 @@ module Ballantine
42
50
 
43
51
  # returns an array to use slack attachments field
44
52
  # reference: https://api.slack.com/messaging/composing/layouts#building-attachments
45
- # @return [Hash] result
46
- def serialize_commits
53
+ # @return [Hash]
54
+ def slack_message
47
55
  message = commits_hash.map do |repo_name, commits|
48
56
  count, word = retrieve_count_and_word(commits)
49
- "*#{repo_name}*: #{count} new #{word}\n#{commits.map(&:message).join("\n")}"
57
+ "*#{repo_name}*: #{count} new #{word}\n" \
58
+ "#{commits.map(&:slack_message).join("\n")}"
50
59
  end.join("\n")
51
60
 
52
61
  {
@@ -2,10 +2,9 @@
2
2
 
3
3
  module Ballantine
4
4
  class CLI < Thor
5
- TYPE_TERMINAL = "terminal"
6
- TYPE_SLACK = "slack"
5
+ include Printable
7
6
 
8
- attr_reader :send_type, :repo
7
+ attr_reader :repo
9
8
 
10
9
  class << self
11
10
  def exit_on_failure?; exit(1) end
@@ -32,14 +31,15 @@ module Ballantine
32
31
  raise NotAllowed, "Environment value must be unique."
33
32
  end
34
33
 
35
- @env = Config::AVAILABLE_ENVIRONMENTS.find { |key| options[key] }
36
- raise AssertionFailed, "Environment value must exist: #{@env}" if @env.nil?
34
+ env = Config::AVAILABLE_ENVIRONMENTS.find { |key| options[key] }
35
+ raise AssertionFailed, "Environment value must exist: #{env}" if env.nil?
37
36
 
37
+ conf.env = env
38
38
  value ? conf.set_data(key, value) : conf.print_data(key)
39
39
  end
40
40
 
41
41
  desc "diff [TARGET] [SOURCE]", "Diff commits between TARGET and SOURCE"
42
- option TYPE_SLACK, type: :boolean, aliases: "-s", default: false, desc: "Send to slack using slack webhook URL."
42
+ option Config::TYPE_SLACK, type: :boolean, aliases: "-s", default: false, desc: "Send to slack using slack webhook URL."
43
43
  def diff(target, source = %x(git rev-parse --abbrev-ref HEAD).chomp)
44
44
  # validate arguments
45
45
  validate(target, source, **options)
@@ -53,8 +53,8 @@ module Ballantine
53
53
  # check commits
54
54
  check_commits(**options)
55
55
 
56
- # send commits
57
- send_commits(target, source, **options)
56
+ # print commits
57
+ print_commits(target, source, **options)
58
58
 
59
59
  exit(0)
60
60
  end
@@ -68,7 +68,7 @@ module Ballantine
68
68
 
69
69
  private
70
70
 
71
- def conf; @conf ||= Config.new(@env) end
71
+ def conf; Config.instance end
72
72
 
73
73
  # @param [String] target
74
74
  # @param [String] source
@@ -87,7 +87,7 @@ module Ballantine
87
87
  raise NotAllowed, "ERROR: target(#{target}) and source(#{source}) can't be equal."
88
88
  end
89
89
 
90
- if options[TYPE_SLACK] && !conf.get_data(Config::KEY_SLACK_WEBHOOK)
90
+ if options[Config::TYPE_SLACK] && !conf.get_data(Config::KEY_SLACK_WEBHOOK)
91
91
  raise NotAllowed, "ERROR: Can't find any slack webhook. Set slack webhook using `ballantine config --#{Config::ENV_LOCAL} slack_webhook [YOUR_WEBHOOK]'."
92
92
  end
93
93
 
@@ -99,8 +99,7 @@ module Ballantine
99
99
  # @param [Hash] options
100
100
  # @return [Boolean]
101
101
  def init_variables(target, source, **options)
102
- @send_type = options[TYPE_SLACK] ? TYPE_SLACK : TYPE_TERMINAL
103
- Repository.send_type = @send_type
102
+ conf.print_type = options[Config::TYPE_SLACK] ? Config::TYPE_SLACK : Config::TYPE_TERMINAL
104
103
  @repo = Repository.find_or_create_by(
105
104
  path: Dir.pwd,
106
105
  remote_url: %x(git config --get remote.origin.url).chomp,
@@ -123,24 +122,23 @@ module Ballantine
123
122
  # @param [String] source
124
123
  # @param [Hash] options
125
124
  # @return [Boolean]
126
- def send_commits(target, source, **options)
125
+ def print_commits(target, source, **options)
127
126
  authors = Author.all
128
127
  if authors.empty?
129
128
  raise ArgumentError, "ERROR: There is no commits between \"#{target}\" and \"#{source}\""
130
129
  end
131
130
 
132
131
  number = authors.size
133
- last_commit = repo.print_last_commit
134
132
 
135
- case send_type
136
- when TYPE_TERMINAL
137
- puts "Check commits before #{repo.name.red} deployment. (#{target.cyan} <- #{source.cyan})".ljust(Repository::DEFAULT_LJUST + 44) + " #{repo.url}/compare/#{repo.from.hash}...#{repo.to.hash}".gray
133
+ case conf.print_type
134
+ when Config::TYPE_TERMINAL
135
+ puts_r "Check commits before #{repo.name.red} deployment. (#{target.cyan} <- #{source.cyan})", "#{repo.url}/compare/#{repo.from.hash}...#{repo.to.hash}".gray
138
136
  puts "Author".yellow + ": #{number}"
139
- puts "Last commit".blue + ": #{last_commit}"
137
+ puts_r "#{"Last commit".blue}: #{repo.to.hash.yellow} #{repo.to.subject}", repo.to.url.gray
140
138
  authors.map(&:print_commits)
141
- when TYPE_SLACK
139
+ when Config::TYPE_SLACK
142
140
  # set message for each author
143
- messages = authors.map(&:serialize_commits)
141
+ messages = authors.map(&:slack_message)
144
142
  actor = %x(git config user.name).chomp
145
143
 
146
144
  # send message to slack
@@ -152,14 +150,14 @@ module Ballantine
152
150
  request.body = JSON.dump({
153
151
  "text" => ":white_check_mark: *#{repo.name}* deployment request by <@#{actor}>" \
154
152
  " (\`<#{repo.url}/tree/#{repo.from.hash}|#{target}>\` <- \`<#{repo.url}/tree/#{repo.to.hash}|#{source}>\` <#{repo.url}/compare/#{repo.from.hash}...#{repo.to.hash}|compare>)" \
155
- "\n:technologist: Author: #{number}\nLast commit: #{last_commit}",
153
+ "\n:technologist: Author: #{number}\nLast commit: #{repo.to.slack_message}",
156
154
  "attachments" => messages,
157
155
  })
158
156
  req_options = { use_ssl: uri.scheme == "https" }
159
157
  response = Net::HTTP.start(uri.hostname, uri.port, req_options) { |http| http.request(request) }
160
158
  puts response.message
161
159
  else
162
- raise AssertionFailed, "Unknown send type: #{send_type}"
160
+ raise AssertionFailed, "Unknown print type: #{conf.print_type}"
163
161
  end
164
162
 
165
163
  true
@@ -2,33 +2,45 @@
2
2
 
3
3
  module Ballantine
4
4
  class Commit
5
- attr_reader :hash, :message # attributes
5
+ attr_reader :hash, :long_hash, :subject # attributes
6
6
  attr_reader :repo, :author # associations
7
7
 
8
8
  class << self
9
9
  # @param [String] hash
10
10
  # @param [Repository] repo
11
- # @param [String] message
12
- # @param [Author, NilClass] message
13
- # @return [Commit]
14
- def find_or_create_by(hash:, repo:, message: nil, author: nil)
11
+ # @return [Commit, NilClass]
12
+ def find(hash:, repo:)
15
13
  @_collections = {} unless defined?(@_collections)
16
- index = "#{hash}-#{repo.name}"
17
- return @_collections[index] unless @_collections[index].nil?
14
+ @_collections["#{hash[...7]}-#{repo.name}"]
15
+ end
18
16
 
19
- @_collections[index] = new(hash:, repo:, message:, author:)
17
+ # @param [String] hash
18
+ # @param [Repository] repo
19
+ # @return [Commit]
20
+ def find_or_create_by(hash:, repo:)
21
+ find(hash:, repo:) || @_collections["#{hash[...7]}-#{repo.name}"] = new(hash:, repo:)
20
22
  end
21
23
  end
22
24
 
23
25
  # @param [String] hash
24
26
  # @param [Repository] repo
25
- # @param [String] message
26
- # @param [Author] author
27
- def initialize(hash:, repo:, message:, author:)
28
- @hash = hash
27
+ def initialize(hash:, repo:)
28
+ @hash = hash[...7]
29
29
  @repo = repo
30
- @message = message
31
- @author = author
30
+ end
31
+
32
+ # @return [Commit]
33
+ def update(**kwargs)
34
+ # TODO: validate keys and values
35
+ kwargs.each { |key, value| instance_variable_set("@#{key}", value) }
36
+ self
37
+ end
38
+
39
+ def url; @url ||= "#{repo.url}/commit/#{long_hash}" end
40
+
41
+ # @return [String]
42
+ def slack_message
43
+ "\`<#{url}|#{hash}>\` #{subject} - #{author.name}"
32
44
  end
33
45
  end
34
46
  end
@@ -2,24 +2,35 @@
2
2
 
3
3
  module Ballantine
4
4
  class Config
5
+ FILE_BALLANTINE_CONFIG = ".ballantine.json"
5
6
  ENV_LOCAL = "local"
6
7
  ENV_GLOBAL = "global"
8
+ TYPE_TERMINAL = "terminal"
9
+ TYPE_SLACK = "slack"
7
10
  AVAILABLE_ENVIRONMENTS = [
8
11
  ENV_LOCAL,
9
12
  ENV_GLOBAL,
10
13
  ].freeze
11
-
12
14
  KEY_SLACK_WEBHOOK = "slack_webhook"
13
15
  AVAILABLE_KEYS = [
14
16
  KEY_SLACK_WEBHOOK,
15
17
  ].freeze
16
18
 
17
- FILE_BALLANTINE_CONFIG = ".ballantine.json"
19
+ attr_reader :data, :loaded
20
+ attr_accessor :env, :print_type
18
21
 
19
- attr_reader :env, :data, :loaded
22
+ class << self
23
+ # @note singleton method
24
+ # @return [Config]
25
+ def instance(...)
26
+ return @_instance if defined?(@_instance)
27
+
28
+ @_instance = new(...)
29
+ end
30
+ end
20
31
 
21
- def initialize(env)
22
- @env = env || ENV_LOCAL
32
+ def initialize
33
+ @env = ENV_LOCAL
23
34
  @data = {}
24
35
  @loaded = false
25
36
  end
@@ -13,21 +13,24 @@ module Ballantine
13
13
  '^ssh://git@(.+)/(.+)/(.+)\.git$', # protocol: ssh -> ssh://git@github.com/oohyun15/ballantine.git
14
14
  ].freeze
15
15
  FILE_GITMODULES = ".gitmodules"
16
- DEFAULT_LJUST = 70
17
16
  PARSER_TOKEN = "!#!#"
18
17
 
19
- attr_reader :name, :path, :owner, :url, :from, :to, :format # attributes
18
+ attr_reader :name, :path, :owner, :from, :to # attributes
20
19
  attr_reader :main_repo, :sub_repos, :commits # associations
21
20
 
22
21
  class << self
22
+ # @param [String] path
23
+ # @return [Repository, NilClass]
24
+ def find(path:)
25
+ @_collections = {} unless defined?(@_collections)
26
+ @_collections[path]
27
+ end
28
+
23
29
  # @param [String] path
24
30
  # @param [String] remote_url
25
31
  # @return [Repository]
26
32
  def find_or_create_by(path:, remote_url: nil)
27
- @_collections = {} unless defined?(@_collections)
28
- return @_collections[path] unless @_collections[path].nil?
29
-
30
- @_collections[path] = new(path:, remote_url:)
33
+ find(path:) || @_collections[path] = new(path:, remote_url:)
31
34
  end
32
35
 
33
36
  # @return [Array<Repository>]
@@ -36,9 +39,6 @@ module Ballantine
36
39
 
37
40
  @_collections.values
38
41
  end
39
-
40
- def send_type; @_send_type end
41
- def send_type=(value); @_send_type = value end
42
42
  end
43
43
 
44
44
  # @param [String] path
@@ -51,10 +51,10 @@ module Ballantine
51
51
  str = remote_url.match(regex)
52
52
  break [str[2], str[3]] if str
53
53
  end
54
- @url = "https://github.com/#{owner}/#{name}"
55
- @format = check_format
56
54
  end
57
55
 
56
+ def url; @url ||= "https://github.com/#{owner}/#{name}" end
57
+
58
58
  # @param [String] target
59
59
  # @param [String] source
60
60
  # @return [Boolean]
@@ -76,7 +76,7 @@ module Ballantine
76
76
  if sub_repos.any?
77
77
  %x(git ls-tree HEAD #{sub_repos.map(&:path).join(" ")}).split("\n").map do |line|
78
78
  _, _, sub_hash, sub_path = line.split(" ")
79
- sub_repo = Repository.find_or_create_by(
79
+ sub_repo = Repository.find(
80
80
  path: path + "/" + sub_path,
81
81
  )
82
82
  sub_commit = Commit.find_or_create_by(
@@ -120,16 +120,9 @@ module Ballantine
120
120
  true
121
121
  end
122
122
 
123
- # @return [String]
124
- def print_last_commit
125
- %x(git --no-pager log --reverse --format="#{check_format(ljust: DEFAULT_LJUST - 12)}" --abbrev=7 #{from.hash}..#{to.hash} -1).strip
126
- end
127
-
128
123
  private
129
124
 
130
- def send_type
131
- self.class.send_type
132
- end
125
+ def conf; Config.instance end
133
126
 
134
127
  # @param [String] name
135
128
  # @return [String] hash
@@ -141,16 +134,15 @@ module Ballantine
141
134
  %x(git rev-list -n 1 #{name}).chomp[0...7]
142
135
  end
143
136
 
144
- # @param [Integer] ljust
145
137
  # @return [String]
146
- def check_format(ljust: DEFAULT_LJUST)
147
- case send_type
148
- when CLI::TYPE_TERMINAL
138
+ def check_format
139
+ case conf.print_type
140
+ when Config::TYPE_TERMINAL
149
141
  " - " + "%h".yellow + " %<(#{ljust})%s " + "#{url}/commit/%H".gray
150
- when CLI::TYPE_SLACK
142
+ when Config::TYPE_SLACK
151
143
  "\\\`<#{url}/commit/%H|%h>\\\` %s - %an"
152
144
  else
153
- raise AssertionFailed, "Unknown send type: #{send_type}"
145
+ raise AssertionFailed, "Unknown print type: #{conf.print_type}"
154
146
  end
155
147
  end
156
148
 
@@ -187,19 +179,26 @@ module Ballantine
187
179
  # @param [Author] author
188
180
  # @return [Array<Commit>]
189
181
  def retrieve_commits(author)
182
+ command = <<~CMD.tr("\n", " ").strip
183
+ git --no-pager log --reverse --no-merges --author="#{author.name}"
184
+ --format="%h#{PARSER_TOKEN}%H#{PARSER_TOKEN}%s"
185
+ --abbrev=7 #{from.hash}..#{to.hash}
186
+ CMD
190
187
  results =
191
- %x(git --no-pager log --reverse --no-merges --author="#{author.name}" --format="%h#{PARSER_TOKEN}#{format}" --abbrev=7 #{from.hash}..#{to.hash})
188
+ %x(#{command})
192
189
  .gsub('"', '\"')
193
190
  .gsub(/[\u0080-\u00ff]/, "")
194
191
  .split("\n")
195
192
 
196
193
  results.map do |result|
197
- hash, message = result.split(PARSER_TOKEN)
194
+ hash, long_hash, subject = result.split(PARSER_TOKEN)
198
195
  Commit.find_or_create_by(
199
196
  hash: hash,
200
197
  repo: self,
201
- message: message,
198
+ ).update(
202
199
  author: author,
200
+ long_hash: long_hash,
201
+ subject: subject,
203
202
  )
204
203
  end
205
204
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ballantine
4
- VERSION = "0.1.4-beta2"
4
+ VERSION = "0.1.4-beta3"
5
5
  end
data/lib/ballantine.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "thor"
4
4
  require "json"
5
5
  require_relative "string"
6
+ require_relative "printable"
6
7
  require_relative "ballantine/version"
7
8
  require_relative "ballantine/config"
8
9
  require_relative "ballantine/author"
data/lib/printable.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Printable
4
+ # @param [String] msg
5
+ # @param [String] msg_r
6
+ # @return [NilClass]
7
+ def puts_r(msg, msg_r)
8
+ size = rjust_size(msg, msg_r)
9
+ puts msg + msg_r.rjust(size)
10
+ end
11
+
12
+ # @param [String] msg
13
+ # @param [String] msg_r
14
+ # @return [Integer]
15
+ def rjust_size(msg, msg_r)
16
+ sanitized = ->(str) { str.sanitize_colored.size + str.scan(/\p{Hangul}/).size }
17
+ cols - sanitized.call(msg) - sanitized.call(msg_r) + msg_r.size
18
+ end
19
+
20
+ # @return [Integer]
21
+ def cols
22
+ return @_cols if defined?(@_cols)
23
+
24
+ require "io/console"
25
+ _lines, @_cols = IO.console.winsize
26
+ @_cols
27
+ end
28
+ end
data/lib/string.rb CHANGED
@@ -16,4 +16,6 @@ class String
16
16
  def yellow; "#{YELLOW}#{self}#{NC}" end
17
17
  def blue; "#{BLUE}#{self}#{NC}" end
18
18
  def cyan; "#{CYAN}#{self}#{NC}" end
19
+
20
+ def sanitize_colored; gsub(/\e\[\d+;?\d*m/, "") end
19
21
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ballantine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4.pre.beta2
4
+ version: 0.1.4.pre.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - oohyun15
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-24 00:00:00.000000000 Z
11
+ date: 2023-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -55,6 +55,7 @@ files:
55
55
  - lib/ballantine/config.rb
56
56
  - lib/ballantine/repository.rb
57
57
  - lib/ballantine/version.rb
58
+ - lib/printable.rb
58
59
  - lib/string.rb
59
60
  homepage: https://github.com/oohyun15/ballantine
60
61
  licenses: