fewald-worklog 0.2.15 → 0.2.18

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: 25cba6c16164da66d60c6ea7f00d3f37a32b2e0cb2fdefd8be7ea862346542a5
4
- data.tar.gz: c094a3fca2e496c9d70684db1fde141695a8db36d1511c4ab01df7764da33e4a
3
+ metadata.gz: 226d608638c12cd6ed618d5669d1e675baf2826ec9f7092887cf08b2612bf845
4
+ data.tar.gz: 897ee2bbd7ee446a2397815632c0738115c7b2ce4e37251ef3197db7cbf1c7fc
5
5
  SHA512:
6
- metadata.gz: 10fdaa8f8ca7ee544d5476c22bac3652eda53548a9d439178cc7b4ab8c7fdd904f8831f779146985d2224f6d6395e310f6d692d45e7fed82c5434a989152d527
7
- data.tar.gz: c6a472717293fbe7ba7dc6a79175c5a9b305c8a14e5039e4e260594b388e90355899a9cf10cc4e95198a1a5621dc9a6542292bd2afdcaa16521da4b6803dbf4c
6
+ metadata.gz: c313a4c546a9aa10ca55c718fda09a9ec3bedd3e16bea9beaea95cfb0153ac1b2ac3be1f8d06f5a5baa60e33d451bfbb270c2f6ddbc31a381462da6e549dd8db
7
+ data.tar.gz: bede43615c16b5c457e953c0f30a902cfaeaa4d55dc7ddcc9d00bdfe6f27e9b40676ee94a88d7c2d89d34b6321bd8e0284fd8233c4144c4ee1864a91505e7091
data/.version CHANGED
@@ -1 +1 @@
1
- 0.2.15
1
+ 0.2.18
data/lib/cli.rb CHANGED
@@ -92,6 +92,7 @@ class WorklogCLI < Thor
92
92
  EOF
93
93
  option :epics_only, type: :boolean, default: false, desc: 'Show only entries that are marked as epic'
94
94
  option :tags, type: :array, default: [], desc: 'Filter entries by tags. Tags are treated as an OR condition.'
95
+ option :project, type: :string, desc: 'Filter entries by project key.'
95
96
  def show
96
97
  worklog = Worklog::Worklog.new
97
98
  worklog.show(options)
data/lib/printer.rb CHANGED
@@ -15,7 +15,15 @@ class Printer
15
15
  # Prints a whole day of work log entries.
16
16
  # If date_inline is true, the date is printed inline with the time.
17
17
  # If epics_only is true, only epic entries are printed.
18
- def print_day(daily_log, date_inline = false, epics_only = false)
18
+ # @param daily_log [DailyLog] The daily log containing entries.
19
+ # @param date_inline [Boolean] If true, the date is printed inline with the time.
20
+ # @param epics_only [Boolean] If true, only epic entries are printed.
21
+ # @param filter [Hash] A hash of filters to apply to the entries.
22
+ # @return [void]
23
+ # @example
24
+ # printer.print_day(daily_log, date_inline: true, epics_only: false, project: 'xyz')
25
+ # printer.print_day(daily_log, date_inline: false, epics_only: true)
26
+ def print_day(daily_log, date_inline = false, epics_only = false, filter = {})
19
27
  daily_log.date = Date.strptime(daily_log.date, '%Y-%m-%d') unless daily_log.date.respond_to?(:strftime)
20
28
 
21
29
  date_string = daily_log.date.strftime('%a, %B %-d, %Y')
@@ -24,6 +32,8 @@ class Printer
24
32
  daily_log.entries.each do |entry|
25
33
  next if epics_only && !entry.epic?
26
34
 
35
+ next unless filter.compact.all? { |k, v| entry.send(k) == v }
36
+
27
37
  print_entry(daily_log, entry, date_inline)
28
38
  end
29
39
  end
data/lib/project.rb CHANGED
@@ -3,8 +3,24 @@
3
3
  module Worklog
4
4
  # Represents a project. A project is a longer running task or initiative.
5
5
  # Single log entries can be associated with a project.
6
+ # @!attribute [rw] key
7
+ # @return [String] Unique identifier for the project, used in log entries.
8
+ # @!attribute [rw] name
9
+ # @return [String] The human-readable name of the project.
10
+ # @!attribute [rw] description
11
+ # @return [String, nil] A description of the project, can be nil
12
+ # @!attribute [rw] start_date
13
+ # @return [Date, nil] The start date of the project, can be nil
14
+ # @!attribute [rw] end_date
15
+ # @return [Date, nil] The end date of the project, can be nil
16
+ # @!attribute [rw] status
17
+ # @return [String, nil] The status of the project, can be nil
18
+ # Possible values: 'active', 'completed', 'archived', etc.
19
+ # Indicates the current state of the project.
20
+ # @!attribute [rw] last_activity
21
+ # @return [Date, nil] The last activity date or nil if not set.
6
22
  class Project
7
- attr_accessor :key, :name, :description, :start_date, :end_date, :status
23
+ attr_accessor :key, :name, :description, :start_date, :end_date, :status, :last_activity
8
24
 
9
25
  # Creates a new Project instance from a hash of attributes.
10
26
  # @param hash [Hash] A hash containing project attributes
@@ -10,6 +10,8 @@ module Worklog
10
10
 
11
11
  # ProjectStorage is responsible for loading and managing project data.
12
12
  # It provides methods to load projects from a YAML file and check if a project exists.
13
+ # @!attribute [w] projects
14
+ # @return [Hash<String, Project>] A hash of projects keyed by their project keys.
13
15
  #
14
16
  # @see Project
15
17
  # @see Configuration
@@ -17,6 +19,11 @@ module Worklog
17
19
  class ProjectStorage
18
20
  attr_writer :projects
19
21
 
22
+ # The name of the YAML file where projects are stored.
23
+ FILE_NAME = 'projects.yaml'
24
+
25
+ # The template for the projects YAML file.
26
+ # This template is used to create a new projects file if it does not exist.
20
27
  PROJECT_TEMPLATE = <<~YAML
21
28
  # Each project is defined by the following attributes:
22
29
  # - key: <project_key>
@@ -44,7 +51,7 @@ module Worklog
44
51
  def load_projects
45
52
  create_template unless file_exist?
46
53
 
47
- file_path = File.join(@configuration.storage_path, 'projects.yml')
54
+ file_path = File.join(@configuration.storage_path, FILE_NAME)
48
55
  projects = {}
49
56
  YAML.load_file(file_path, permitted_classes: [Date])&.each do |project_hash|
50
57
  project = Project.from_hash(project_hash)
@@ -54,12 +61,14 @@ module Worklog
54
61
  projects
55
62
  end
56
63
 
57
- # Check if a project with a given handle exists.
58
- # @param handle [String] The handle of the project to check.
64
+ # Check if a project with a given key exists.
65
+ # @param key [String] The key of the project to check.
59
66
  # @return [Boolean] Returns true if the project exists, false otherwise.
60
- def exist?(handle)
67
+ # @note This method loads the projects from disk if they are not already loaded.
68
+ # @see load_projects
69
+ def exist?(key)
61
70
  projects = load_projects
62
- projects.key?(handle)
71
+ projects.key?(key)
63
72
  end
64
73
 
65
74
  private
@@ -67,12 +76,20 @@ module Worklog
67
76
  # Check whether projects.yaml exists in the project_dir
68
77
  # @return [Boolean] Returns true if the project YAML file exists, false otherwise
69
78
  def file_exist?
70
- file_path = File.join(@configuration.storage_path, 'projects.yml')
79
+ file_path = File.join(@configuration.storage_path, FILE_NAME)
71
80
  File.exist?(file_path)
72
81
  end
73
82
 
83
+ # Creates a template for the projects YAML file if it does not exist.
84
+ # This method writes a predefined template to the projects.yml file.
85
+ # @return [void]
86
+ # @note This method will overwrite any existing projects.yml file.
87
+ # @see PROJECT_TEMPLATE for the structure of the template.
74
88
  def create_template
75
- File.write(File.join(@configuration.storage_path, 'projects.yml'), PROJECT_TEMPLATE)
89
+ return unless @configuration.storage_path_exist?
90
+
91
+ File.write(File.join(@configuration.storage_path, FILE_NAME), PROJECT_TEMPLATE)
92
+ nil
76
93
  end
77
94
  end
78
95
  end
data/lib/storage.rb CHANGED
@@ -93,8 +93,6 @@ class Storage
93
93
  # Create file for a new day if it does not exist
94
94
  # @param [Date] date The date, used as the file name.
95
95
  def create_file_skeleton(date)
96
- create_folder
97
-
98
96
  File.write(filepath(date), YAML.dump(DailyLog.new(date:, entries: []))) unless File.exist?(filepath(date))
99
97
  end
100
98
 
@@ -119,8 +117,6 @@ class Storage
119
117
  end
120
118
 
121
119
  def write_log(file, daily_log)
122
- create_folder
123
-
124
120
  WorkLogger.debug "Writing to file #{file}"
125
121
 
126
122
  File.open(file, 'w') do |f|
@@ -162,8 +158,6 @@ class Storage
162
158
  # Write people to the people file
163
159
  # @param [Array<Person>] people List of people
164
160
  def write_people!(people)
165
- create_folder
166
-
167
161
  people_file = File.join(@config.storage_path, 'people.yaml')
168
162
  File.open(people_file, 'w') do |f|
169
163
  f.puts people.to_yaml
@@ -171,7 +165,10 @@ class Storage
171
165
  end
172
166
 
173
167
  # Create folder if not exists already.
174
- def create_folder
168
+ def create_default_folder
169
+ # Do nothing if the storage path is not the default path
170
+ return unless @config.default_storage_path?
171
+
175
172
  Dir.mkdir(@config.storage_path) unless Dir.exist?(@config.storage_path)
176
173
  end
177
174
 
data/lib/worklog.rb CHANGED
@@ -22,6 +22,22 @@ module Worklog
22
22
  # Main class providing all worklog functionality.
23
23
  # This class is the main entry point for the application.
24
24
  # It handles command line arguments, configuration, and logging.
25
+ # @!attribute [r] config
26
+ # @return [Configuration] The configuration object containing settings for the application.
27
+ # @!attribute [r] storage
28
+ # @return [Storage] The storage object for managing file operations.
29
+ #
30
+ # @see Configuration
31
+ # @see Storage
32
+ # @see ProjectStorage
33
+ #
34
+ # @example
35
+ # worklog = Worklog.new
36
+ # worklog.add('Worked on feature X',
37
+ # date: '2023-10-01',
38
+ # time: '10:00:00',
39
+ # tags: ['feature', 'x'],
40
+ # ticket: 'TICKET-123')
25
41
  class Worklog
26
42
  include StringHelper
27
43
  attr_reader :config, :storage
@@ -31,6 +47,13 @@ module Worklog
31
47
  @storage = Storage.new(@config)
32
48
 
33
49
  WorkLogger.level = @config.log_level == :debug ? Logger::Severity::DEBUG : Logger::Severity::INFO
50
+
51
+ bootstrap
52
+ end
53
+
54
+ # Bootstrap the worklog application.
55
+ def bootstrap
56
+ @storage.create_default_folder
34
57
  end
35
58
 
36
59
  # Add new entry to the work log.
@@ -92,6 +115,20 @@ module Worklog
92
115
  WorkLogger.info Rainbow("Updated work log for #{options[:date]}").green
93
116
  end
94
117
 
118
+ # Show the work log for a specific date range or a single date.
119
+ #
120
+ # @param options [Hash] the options hash containing date range or single date.
121
+ # @option options [Integer] :days the number of days to show from today (default: 1).
122
+ # @option options [String] :from the start date in 'YYYY-MM-DD' format.
123
+ # @option options [String] :to the end date in 'YYYY-MM-DD' format.
124
+ # @option options [String] :date a specific date in 'YYYY-MM-DD' format.
125
+ # @option options [Boolean] :epics_only whether to show only entries with epics (default: false).
126
+ # @option options [String] :project the project key to filter entries by project.
127
+ #
128
+ # @example
129
+ # worklog.show(days: 7)
130
+ # worklog.show(from: '2023-10-01', to: '2023-10-31')
131
+ # worklog.show(date: '2023-10-01')
95
132
  def show(options = {})
96
133
  people = @storage.load_people!
97
134
  printer = Printer.new(people)
@@ -103,7 +140,7 @@ module Worklog
103
140
  printer.no_entries(start_date, end_date)
104
141
  else
105
142
  entries.each do |entry|
106
- printer.print_day(entry, entries.size > 1, options[:epics_only])
143
+ printer.print_day(entry, entries.size > 1, options[:epics_only], project: options[:project])
107
144
  end
108
145
  end
109
146
  end
@@ -170,8 +207,8 @@ module Worklog
170
207
  projects.each_value do |project|
171
208
  puts "#{Rainbow(project.name).gold} (#{project.key})"
172
209
  puts " Description: #{project.description}" if project.description
173
- puts " Start date: #{project.start_date}" if project.start_date
174
- puts " End date: #{project.end_date}" if project.end_date
210
+ puts " Start date: #{project.start_date.strftime('%b %d, %Y')}" if project.start_date
211
+ puts " End date: #{project.end_date.strftime('%b %d, %Y')}" if project.end_date
175
212
  puts " Status: #{project.status}" if project.status
176
213
  end
177
214
  puts 'No projects found.' if projects.empty?
@@ -326,6 +363,15 @@ module Worklog
326
363
  [start_date, end_date]
327
364
  end
328
365
 
366
+ # Validate that the project exists in the project storage if a project key is provided.
367
+ #
368
+ # @param project_key [String] the project key to validate
369
+ # @raise [ProjectNotFoundError] if the project does not exist
370
+ #
371
+ # @return [void]
372
+ #
373
+ # @example
374
+ # validate_projects!('P001')
329
375
  def validate_projects!(project_key)
330
376
  project_storage = ProjectStorage.new(@config)
331
377
  begin
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fewald-worklog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.15
4
+ version: 0.2.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Friedrich Ewald