wlog 1.1.7 → 1.2.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +100 -39
  3. data/lib/wlog/commands/bootstrap_templates.rb +5 -0
  4. data/lib/wlog/commands/delete_attachment.rb +17 -0
  5. data/lib/wlog/commands/fetch_git_commits.rb +45 -0
  6. data/lib/wlog/commands/fetch_git_commits_standard.rb +29 -0
  7. data/lib/wlog/commands/innit_db.rb +3 -2
  8. data/lib/wlog/commands/write_template.rb +22 -0
  9. data/lib/wlog/domain/attachment.rb +26 -54
  10. data/lib/wlog/domain/git_commit.rb +11 -0
  11. data/lib/wlog/domain/issue.rb +14 -1
  12. data/lib/wlog/domain/key_value.rb +1 -1
  13. data/lib/wlog/domain/template_helper.rb +21 -0
  14. data/lib/wlog/migrations/fix_attachments_polymorphic_table.rb +15 -0
  15. data/lib/wlog/migrations/make_standard_tables.rb +0 -13
  16. data/lib/wlog/tech/git_commit_parser.rb +48 -0
  17. data/lib/wlog/tech/git_commit_printer.rb +19 -0
  18. data/lib/wlog/tech/uncolored_string.rb +1 -1
  19. data/lib/wlog/ui/bootstrap.rb +1 -0
  20. data/lib/wlog/ui/cli_interface.rb +2 -58
  21. data/lib/wlog/ui/edit_handler.rb +7 -0
  22. data/lib/wlog/ui/git_ui.rb +47 -0
  23. data/lib/wlog/ui/invoice_ui.rb +53 -36
  24. data/lib/wlog/ui/issue_ui.rb +57 -5
  25. data/lib/wlog/ui/template_ui.rb +2 -2
  26. data/lib/wlog/version.rb +1 -1
  27. data/spec/domain/attachment_spec.rb +49 -55
  28. data/spec/domain/commands/concat_desc_spec.rb +1 -0
  29. data/spec/domain/commands/new_entry_spec.rb +1 -0
  30. data/spec/domain/commands/replace_pattern_spec.rb +1 -0
  31. data/spec/domain/git_commits_spec.rb +85 -0
  32. data/spec/domain/invoice_spec.rb +35 -0
  33. data/spec/domain/issue_spec.rb +1 -0
  34. data/spec/domain/key_value_spec.rb +1 -0
  35. data/spec/domain/log_entry_spec.rb +1 -0
  36. data/spec/domain/sys_config_spec.rb +1 -0
  37. data/spec/spec_helper.rb +31 -0
  38. data/wlog.gemspec +3 -1
  39. metadata +40 -18
  40. data/lib/wlog/domain/session.rb +0 -17
  41. data/lib/wlog/domain/sql_modules/polymorphic_attachments_sql.rb +0 -24
  42. data/lib/wlog/domain/template_engine.rb +0 -55
  43. data/lib/wlog/sql/mono/1.sql +0 -50
  44. data/lib/wlog/sql/seq/.gitkeep +0 -0
  45. data/lib/wlog/sql/seq/2.sql +0 -4
  46. data/lib/wlog/sql/seq/3.sql +0 -3
  47. data/lib/wlog/ui/commands/ui_command.rb +0 -9
@@ -0,0 +1,11 @@
1
+ module Wlog
2
+ # A git commit message
3
+ # @author Simon Symeonidis
4
+ class GitCommit
5
+ def initialize
6
+ @commit = @author = @shortlog = @message = ""
7
+ end
8
+
9
+ attr_accessor :commit, :author, :shortlog, :message
10
+ end
11
+ end
@@ -12,6 +12,7 @@ module Wlog
12
12
  class Issue < ActiveRecord::Base
13
13
 
14
14
  has_many :log_entries, dependent: :delete_all
15
+ has_many :attachments, as: :attachable
15
16
 
16
17
  StatusNew = 0
17
18
  StatusStarted = 1
@@ -40,7 +41,9 @@ class Issue < ActiveRecord::Base
40
41
  "#{@strmaker.yellow('Summary')} #{$/}"\
41
42
  " #{description}#{$/ + $/}"\
42
43
  "#{@strmaker.yellow('Description')} #{$/}"\
43
- " #{Helpers.break_string(long_description, 80)}#{$/ + $/}"
44
+ " #{Helpers.break_string(long_description, 80)}#{$/ + $/}"\
45
+ "#{@strmaker.yellow('Files')}#{$/}"\
46
+ "#{attachments_s}"
44
47
  end
45
48
 
46
49
  # Mark issue as started
@@ -65,6 +68,16 @@ private
65
68
  StatusFinished => "finished",
66
69
  StatusArchived => "archived"}
67
70
 
71
+ # Stringify attachments for terminal output
72
+ def attachments_s
73
+ str = ''
74
+ self.attachments.each do |att|
75
+ str.concat(att.to_s)
76
+ end
77
+ str = @strmaker.red(" N/A#{$/}") if str == '' # no attachments
78
+ str.concat($/)
79
+ str end
80
+
68
81
  private_class_method
69
82
 
70
83
  end # class Issue
@@ -19,7 +19,7 @@ class KeyValue < ActiveRecord::Base
19
19
  ret = KeyValue.new(:key => key, :value => value)
20
20
  end
21
21
  ret.save
22
- end
22
+ nil end
23
23
 
24
24
  # Get a certain value by key
25
25
  # @return the value given the key. nil if not found
@@ -0,0 +1,21 @@
1
+ require 'wlog/domain/key_value'
2
+ require 'wlog/domain/static_configurations'
3
+
4
+ module Wlog
5
+ # Bunlde helper functions for templates here
6
+ # @author Simon Symeonidis
7
+ class TemplateHelper
8
+ include StaticConfigurations
9
+ # @return absolute path to the template the user has set
10
+ def self.template_file
11
+ num = KeyValue.get('template') || 1
12
+ Dir[TemplateDir + '*'][num.to_i - 1]
13
+ end
14
+
15
+ # @return template contents of the current selected template
16
+ def self.template_s
17
+ File.read(TemplateHelper.template_file)
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_record'
2
+
3
+ module Wlog
4
+ # Add type, id polymorphic fields
5
+ # @author Simon Symeonidis
6
+ # @date Sun Oct 5 22:43:12 EDT 2014
7
+ class FixAttachmentsPolymorphicTable < ActiveRecord::Migration
8
+
9
+ def change
10
+ add_column :attachments, :attachable_id, :integer
11
+ add_column :attachments, :attachable_type, :text
12
+ end
13
+
14
+ end
15
+ end
@@ -44,16 +44,3 @@ class MakeStandardTables < ActiveRecord::Migration
44
44
  end
45
45
  end
46
46
 
47
-
48
- =begin
49
- TODO
50
- -- A polymorphic relationship for attachments. So pretty much anything that
51
- -- wants to have something attached, uses the discriminator in order to
52
- -- specify itself, as well as its id.
53
- CREATE TABLE polymorphic_attachments (
54
- discriminator TEXT,
55
- discriminator_id INTEGER,
56
- attachment_id INTEGER
57
- );
58
-
59
- =end
@@ -0,0 +1,48 @@
1
+ require 'wlog/domain/git_commit'
2
+ module Wlog
3
+ # Parses git text from a `git log` command invocation
4
+ # @author Simon Symeonidis
5
+ class GitCommitParser
6
+ # @param log_s is the string obtained from running a `git log` command
7
+ # @return a list of GitCommit objects
8
+ def self.parse(log_s)
9
+ cur = nil
10
+ inmessage = false
11
+ gitlogs = []
12
+
13
+ log_s.lines.each do |line|
14
+ case line
15
+ when /^commit/i
16
+ inmessage = false
17
+ gitlogs.push cur if cur
18
+ cur = GitCommit.new
19
+ cur.commit = line.split[1].strip
20
+
21
+ when /^author/i
22
+ next unless cur
23
+ cur.author = line.split[1].strip
24
+
25
+ when /^date/i, /^\n$/
26
+ next
27
+
28
+ else
29
+ next unless cur
30
+ if inmessage
31
+ cur.message.concat(line)
32
+ cur.message.strip!
33
+ else
34
+ cur.shortlog = line
35
+ cur.shortlog.strip!
36
+ inmessage = true
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ # if commits have no hash, discard them
43
+ gitlogs.reject! { |e| e.commit == "" }
44
+ gitlogs.push cur if cur
45
+ gitlogs end
46
+
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ require 'wlog/domain/sys_config'
2
+ module Wlog
3
+ # Cute printer for git commit logs
4
+ # @author Simon Symeonidis
5
+ module GitCommitPrinter
6
+
7
+ def print_git_commits(commit_a)
8
+ sm = SysConfig.string_decorator
9
+
10
+ commit_a.each do |commit|
11
+ print ' '
12
+ print sm.blue(commit.commit)
13
+ print ' '
14
+ puts sm.green(commit.shortlog[0..50] + ' ...')
15
+ end
16
+ nil end
17
+
18
+ end
19
+ end
@@ -1,7 +1,7 @@
1
1
  module Wlog
2
2
  # Use this if the system does not support colored strings.
3
3
  # @author Simon Symeonidis
4
- class UncoloredString
4
+ class UncoloredString # :nodoc:
5
5
  def self.red(str); str end
6
6
  def self.yellow(str); str end
7
7
  def self.magenta(str); str end
@@ -7,6 +7,7 @@ module Wlog
7
7
  # point of the application and, the first transaction you require.
8
8
  # @author Simon Symeonidis
9
9
  class Bootstrap
10
+ # make $HOME/.config/wlog standard dirs, and pull up database
10
11
  def self.configure!
11
12
  Helpers.make_dirs!
12
13
  InnitDb.new.execute
@@ -2,7 +2,6 @@ require 'readline'
2
2
  require 'wlog/domain/issue'
3
3
  require 'wlog/domain/static_configurations'
4
4
  require 'wlog/domain/sys_config'
5
- require 'wlog/domain/attachment'
6
5
  require 'wlog/domain/helpers'
7
6
 
8
7
  require 'wlog/commands/create_issue'
@@ -14,6 +13,7 @@ require 'wlog/commands/delete_issue'
14
13
  require 'wlog/ui/issue_ui'
15
14
  require 'wlog/ui/template_ui'
16
15
  require 'wlog/ui/invoice_ui'
16
+ require 'wlog/ui/git_ui'
17
17
 
18
18
  module Wlog
19
19
  # @author Simon Symeonidis
@@ -38,9 +38,6 @@ class CliInterface
38
38
 
39
39
  case cmd
40
40
  when /^archive/ then archive cmd
41
- when /^showattach/ then show_attach
42
- when /^outattach/ then output_attach
43
- when /^attach/ then attach
44
41
  when /^focus/ then focus(cmd)
45
42
  when /new/ then new_issue
46
43
  when /^(ls|show)/ then show_issues
@@ -49,6 +46,7 @@ class CliInterface
49
46
  when /^help/ then print_help
50
47
  when /^search/ then search
51
48
  when /^config/ then config
49
+ when /^git/ then GitUi.new.run
52
50
  when /^templates/ then TemplateUi.new.run
53
51
  when /^invoices/ then InvoiceUi.new.run
54
52
  end
@@ -93,32 +91,6 @@ private
93
91
 
94
92
  puts "No such issue" unless dcmd.deleted?
95
93
  end
96
-
97
- # Wriet out the data contained in the database of the attachment
98
- def output_attach
99
- puts "Migration of implementation pending"
100
- return
101
-
102
- att_id = Readline.readline('Which attachment to output? : ').to_i
103
- loc = Readline.readline('Output where (abs dir) ? : ')
104
- loc.chomp!
105
- att = Attachment.find(@db, Issue.name, att_id)
106
-
107
- fh = File.open("#{loc}/#{att.filename}", 'w')
108
- fh.write(att.data)
109
- fh.close
110
- end
111
-
112
- def show_attach
113
- puts "Migration of implementation pending"
114
- return
115
- issue_id = Readline.readline('Which issue id? : ').to_i
116
- atts = Attachment.find_all_by_discriminator(@db, Issue.name, issue_id)
117
- atts.each do |att|
118
- printf "[%d] - %s (alias: %s)\n", att.id, att.filename, att.given_name
119
- end
120
- end
121
-
122
94
  # Archive means set status to 3 (arhive status) to the listed issues
123
95
  def archive(cmd)
124
96
  args = cmd.split[1..-1]
@@ -139,32 +111,6 @@ private
139
111
  end
140
112
  end
141
113
 
142
- def attach
143
- puts "Migration of implementation pending"
144
- return
145
-
146
- issue_id = Readline.readline('Attach to issue id: ').to_i
147
- loc = Readline.readline('Absolute file location: ')
148
- loc.strip!
149
- name_alias = Readline.readline('Alias name for file (optional): ')
150
- name_alias.strip!
151
-
152
- unless loc.nil?
153
- fh = File.open(loc, "r")
154
- data = fh.read
155
- fh.close
156
-
157
- att = Attachment.new(@db, Issue.name, issue_id)
158
- att.data = data
159
- att.filename = loc.split('/').last
160
- att.given_name = name_alias
161
- att.insert
162
- puts 'Attached file.'
163
- else
164
- puts 'You need to provide a proper path.'
165
- end
166
- end
167
-
168
114
  # Focus on an issue to log work etc
169
115
  def focus(cmd)
170
116
  issue_id = cmd.split[1]
@@ -200,8 +146,6 @@ private
200
146
  'end', 'Exit the progam',
201
147
  'delete', 'Remove the issue with a given id',
202
148
  'archive', 'Archive a file into a specific issue',
203
- 'showattach', 'Show what files have been attached to an issue',
204
- 'outattach', 'Extract a file from the database',
205
149
  'invoices', 'Go to invoices interface',
206
150
  'templates', 'Go to template interface, and set templates',
207
151
  'focus', 'Focus on a particular ',
@@ -1,6 +1,8 @@
1
1
  require 'wlog/domain/sys_config'
2
2
 
3
3
  module Wlog
4
+ # Provides a bunch of edit helping functions for altering already inserted
5
+ # information about issues.
4
6
  # @author Simon Symeonidis
5
7
  class EditHandler
6
8
 
@@ -36,7 +38,9 @@ class EditHandler
36
38
  end
37
39
  end
38
40
 
41
+ # Small helper to parse the due date when editing the dates of issues.
39
42
  # @param time is the date-time in string format (eg Oct 28)
43
+ # @return nothing - we're just setting if the data format is ok
40
44
  def edit_time(time)
41
45
  date_time = time_handle(time)
42
46
  @issue.update(:due_date => date_time)
@@ -46,6 +50,9 @@ class EditHandler
46
50
  "Invalid date/time format. Try format like 'Oct 28'"
47
51
  end
48
52
 
53
+ # Edit the reported date of an issue, given a date string in the format of
54
+ # 'Oct 28'.
55
+ # @param time_str is the time in string format
49
56
  def edit_reported_time(time_str)
50
57
  date_time = time_handle(time_str)
51
58
  @issue.reported_date = date_time.to_time
@@ -0,0 +1,47 @@
1
+ require 'wlog/domain/sys_config'
2
+ module Wlog
3
+ # Interface to setup git stuff.
4
+ # @author Simon Symeonidis
5
+ class GitUi
6
+
7
+ def initialize
8
+ @strmaker = SysConfig.string_decorator
9
+ end
10
+
11
+ def run
12
+ cmd = "default"
13
+
14
+ until cmd == "end" do
15
+ cmd = Readline.readline("[#{@strmaker.blue('git')}] ")
16
+
17
+ case cmd
18
+ when /^set/
19
+ path = Readline.readline("Path to git repo (eg: project/.git/): ")
20
+
21
+ unless File.directory? path
22
+ puts @strmaker.red("That doesn't look like a git repo. Nothing done")
23
+ next
24
+ end
25
+
26
+ author = Readline.readline("git author: ")
27
+
28
+ # Set the git repo in the db (so one git repo per db)
29
+ KeyValue.put!("git", path)
30
+ KeyValue.put!("author", author)
31
+
32
+ when /^unset/
33
+ KeyValue.put!("git", "")
34
+
35
+ when /^(ls|show)/
36
+ print ' repo: '
37
+ puts @strmaker.green(KeyValue.get("git"))
38
+ print ' auth: '
39
+ puts @strmaker.yellow(KeyValue.get("author"))
40
+
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+
@@ -2,6 +2,11 @@ require 'readline'
2
2
  require 'wlog/domain/invoice'
3
3
  require 'wlog/domain/sys_config'
4
4
  require 'wlog/domain/static_configurations'
5
+ require 'wlog/domain/template_helper'
6
+ require 'wlog/commands/write_template'
7
+ require 'wlog/commands/fetch_git_commits'
8
+ require 'wlog/commands/fetch_git_commits_standard'
9
+ require 'wlog/tech/git_commit_printer'
5
10
  require 'erb'
6
11
 
7
12
  module Wlog
@@ -9,6 +14,7 @@ module Wlog
9
14
  # @author Simon Symeonidis
10
15
  class InvoiceUi
11
16
  include StaticConfigurations
17
+ include GitCommitPrinter
12
18
 
13
19
  def initialize
14
20
  @strmaker = SysConfig.string_decorator
@@ -24,6 +30,8 @@ class InvoiceUi
24
30
  when /^(ls|show)/ then ls
25
31
  when /^delete/ then delete(cmd.split.drop 1)
26
32
  when /^generate/ then generate(cmd.split.drop 1)
33
+ when /^commits/ then commits(cmd.split.drop 1)
34
+ when 'help' then print_help
27
35
  when /^end/ then next
28
36
  else
29
37
  puts "type 'help' for a list of options"
@@ -36,25 +44,19 @@ private
36
44
  # TODO maybe separate this in the future for better testing.
37
45
  def generate(rest)
38
46
  num = rest.first || 1
47
+
39
48
  @invoice = Invoice.find(num.to_i)
40
-
41
- # NOTE: these need to be instance vars, so we expose them to ERB later on
42
- @les = @invoice.log_entries_within_dates
43
- @issues = [Issue.find(*(@les.collect(&:issue_id).uniq))].compact.flatten
44
-
45
- # Get the template
46
- num = SysConfig.get_config('template') || 1
47
- tpath = Dir[TemplateDir + '*'][num.to_i - 1]
48
- template_s = File.read(tpath)
49
+ cmd = FetchGitCommitsStandard.new(@invoice.from, @invoice.to)
50
+ cmd.execute
49
51
 
50
- renderer = ERB.new(template_s)
52
+ @log_entries = @invoice.log_entries_within_dates
53
+ @issues = [Issue.find(*(@log_entries.collect(&:issue_id).uniq))].compact.flatten
54
+ @commits = cmd.commits
55
+
56
+ renderer = ERB.new(TemplateHelper.template_s)
51
57
  output = renderer.result(binding)
52
58
 
53
- FileUtils.mkdir_p TemplateOutputDir
54
- template_ext = tpath.split(File::SEPARATOR).last.split('.').last
55
- filename = TemplateOutputDir + "#{@invoice.id}-invoice.#{template_ext}"
56
-
57
- File.write(filename, output)
59
+ WriteTemplate.new(output, @invoice).execute
58
60
 
59
61
  rescue ActiveRecord::RecordNotFound
60
62
  puts 'No such invoice'
@@ -105,29 +107,44 @@ private
105
107
  # TODO: this would have to be factored out at some point. Also I think the
106
108
  # implementation is crappy. I have to recheck at some point.
107
109
  def longtext
108
- times = 3
109
- str = ""
110
- count = 0
111
-
112
- while times != 0 do
113
- cur = Readline.readline()
114
- str.concat(cur)
115
- str.concat($/)
116
- if ["", nil].include? cur
117
- str.concat($/)
118
- count += 1
119
- if count == 2
120
- times -= 1
121
- count = 0
122
- end
123
- else
124
- # reset blank line count. The user will have to hammer enter a few times
125
- # to escape from this menu
126
- count = 0
127
- end
128
- end
110
+ count = 0
111
+ status = nil
112
+ str = ""
113
+
114
+ until status == :end_text do
115
+ line = Readline.readline(@strmaker.blue('> ')).strip
116
+ count += 1 if line == ""
117
+ count = 0 if line != ""
118
+
119
+ str.concat(line).concat($/)
120
+
121
+ status = :end_text and next if count == 2
122
+ end
129
123
  str end
130
124
 
125
+ def commits(invoice_id)
126
+ inv = Invoice.find_by_id(invoice_id)
127
+ repo = KeyValue.get('git')
128
+ author = KeyValue.get('author')
129
+
130
+ unless repo
131
+ puts @strmaker.red("You need to set a git repo first")
132
+ return
133
+ end
134
+
135
+ command = FetchGitCommits.new(inv.from, inv.to, repo, author)
136
+ command.execute
137
+
138
+ puts
139
+ print ' '
140
+ puts "git commits for #{@strmaker.yellow(author)}"
141
+ puts
142
+ print_git_commits(command.commits)
143
+
144
+ rescue ActiveRecord::RecordNotFound
145
+ puts @strmaker.red("No such invoice")
146
+ end
147
+
131
148
  end
132
149
  end
133
150