wlog 1.1.7 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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