snitcher_reports 0.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 +7 -0
  2. data/.snitcher.yml.example +135 -0
  3. data/CHANGELOG.md +9 -0
  4. data/LICENSE +21 -0
  5. data/README.md +685 -0
  6. data/lib/snitcher/anomaly.rb +24 -0
  7. data/lib/snitcher/anomaly_context.rb +76 -0
  8. data/lib/snitcher/anomaly_detector.rb +32 -0
  9. data/lib/snitcher/anomaly_rules/base.rb +29 -0
  10. data/lib/snitcher/anomaly_rules/commits_without_closed_tickets.rb +22 -0
  11. data/lib/snitcher/anomaly_rules/estimate_overrun.rb +37 -0
  12. data/lib/snitcher/anomaly_rules/excessive_meeting_time.rb +43 -0
  13. data/lib/snitcher/anomaly_rules/inactive_working_days.rb +32 -0
  14. data/lib/snitcher/anomaly_rules/time_above_availability.rb +27 -0
  15. data/lib/snitcher/client.rb +177 -0
  16. data/lib/snitcher/configuration.rb +123 -0
  17. data/lib/snitcher/holiday_region_resolver.rb +123 -0
  18. data/lib/snitcher/jql_validator.rb +44 -0
  19. data/lib/snitcher/meetings_aggregator.rb +38 -0
  20. data/lib/snitcher/orchestrator.rb +227 -0
  21. data/lib/snitcher/presenters/html.rb +87 -0
  22. data/lib/snitcher/presenters/markdown.rb +140 -0
  23. data/lib/snitcher/presenters/presenter.rb +90 -0
  24. data/lib/snitcher/report.rb +112 -0
  25. data/lib/snitcher/report_service.rb +128 -0
  26. data/lib/snitcher/report_writer.rb +74 -0
  27. data/lib/snitcher/sources/clickup/archived_lists.rb +174 -0
  28. data/lib/snitcher/sources/clickup/working_hours_filter.rb +88 -0
  29. data/lib/snitcher/sources/clickup.rb +467 -0
  30. data/lib/snitcher/sources/git/command_runner.rb +198 -0
  31. data/lib/snitcher/sources/git.rb +347 -0
  32. data/lib/snitcher/sources/google_calendar.rb +328 -0
  33. data/lib/snitcher/sources/jira/client.rb +346 -0
  34. data/lib/snitcher/sources/jira/status_categories.rb +60 -0
  35. data/lib/snitcher/sources/jira.rb +523 -0
  36. data/lib/snitcher/sources/linear.rb +257 -0
  37. data/lib/snitcher/sources/source.rb +140 -0
  38. data/lib/snitcher/templates/report.html.erb +564 -0
  39. data/lib/snitcher/templates/snitcher-logo.png +0 -0
  40. data/lib/snitcher/time_formatter.rb +27 -0
  41. data/lib/snitcher/validators.rb +59 -0
  42. data/lib/snitcher/version.rb +5 -0
  43. data/lib/snitcher/work_item.rb +75 -0
  44. data/lib/snitcher/working_hours_calculator.rb +205 -0
  45. data/lib/snitcher/working_hours_config.rb +208 -0
  46. data/lib/snitcher.rb +39 -0
  47. metadata +250 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 77c2bf289fd3ba179a8887bc78c48382583f2fde533f4fdd26d37da7b696aaa8
4
+ data.tar.gz: aa5969150911043f511b11b95e76caced6086498052873d7055accd2cf341116
5
+ SHA512:
6
+ metadata.gz: 287d3f7a2d68646a6ddcb507df366cb85c7ccf2bb6f0e43403380b36327d46d78d9ae6de9262c90d3fa38cacce045ed09a6867674abbafe68ff6a03c5fb2cc66
7
+ data.tar.gz: 2c9c951e9fbe7e8f5dd23909608026cc034a5d4a5c5d48ae8b926fb477f396181831fa779e5dd3b81bcaee315ba3d7262002a314da1a37b0c3afcfed428af625
@@ -0,0 +1,135 @@
1
+ # Snitcher project configuration
2
+ #
3
+ # Status names are language-specific (e.g. Polish, German), so the values below are
4
+ # only a starting point — replace them with the names your workspace actually uses.
5
+ #
6
+ # Copy this file to .snitcher.yml and adjust the values to match your workspace.
7
+
8
+ version: 1
9
+ sources:
10
+ clickup:
11
+ # Optional: limit reports to specific ClickUp spaces.
12
+ # Omit or leave empty to include all spaces. Names are case-sensitive.
13
+ # This also limits where archived lists are looked for.
14
+ # spaces:
15
+ # - Engineering
16
+ # - QA
17
+ # NOTE: done_statuses and in_progress_statuses are NOT used to filter tasks fetched
18
+ # from ClickUp. The request narrows by date_done_gt/lt, the only completion-date
19
+ # parameter the API accepts, and the report then keeps the tasks whose date_closed
20
+ # falls inside the period. Dates are more reliable than status names — lists and
21
+ # folders can override workspace-level statuses via the override_statuses flag, so
22
+ # status names are not consistent across a workspace.
23
+ # These values are kept for potential future use (e.g. list/folder-scoped reports).
24
+ done_statuses:
25
+ - "complete"
26
+ - "closed"
27
+ in_progress_statuses:
28
+ - "in progress"
29
+ todo_statuses:
30
+ - "to do"
31
+ - "open"
32
+ jira:
33
+ # Optional: limit reports to specific JIRA projects.
34
+ # Omit or leave empty to include all projects.
35
+ # projects:
36
+ # - SCRUM
37
+ # - XSP
38
+ # NOTE: leave the status lists out unless your classification differs from Jira's
39
+ # own. Snitcher reads each status's category from the instance itself
40
+ # (/rest/api/3/status), which is language-independent and covers statuses added
41
+ # later, and the names below take precedence over it — filling them in with Jira's
42
+ # own defaults replaces a correct answer with a frozen copy of it. Set them to
43
+ # override Jira, e.g. to count "In Review" as active work when Jira files it as
44
+ # not-started:
45
+ # in_progress_statuses:
46
+ # - "In Review"
47
+ linear:
48
+ done_statuses:
49
+ - "Done"
50
+ - "Cancelled"
51
+ in_progress_statuses:
52
+ - "In Progress"
53
+ - "In Review"
54
+ todo_statuses:
55
+ - "Todo"
56
+ - "Backlog"
57
+ git:
58
+ # Optional: path to the git repository (default: current directory).
59
+ # repo_path: /path/to/your/project
60
+ #
61
+ # Git identity resolution (both `user` and `emails` accept a single string OR a
62
+ # list of strings, since one person may commit under several addresses — work
63
+ # laptop, personal, GitHub noreply):
64
+ #
65
+ # A requested email (--users / user_email) is translated through the `emails`
66
+ # map when there is a matching entry, and used as-is when there is none. The
67
+ # rule is the same whether one user or several are requested: a named address
68
+ # is never swapped for a different one, because nothing here says whose address
69
+ # was named. An email that matches no commits yields an empty report — never
70
+ # another person's data.
71
+ #
72
+ # `user` — the default git commit email(s), used when NO --users / user_email is
73
+ # given (run it for yourself without --users). Every source reads its own
74
+ # `user`, so git and google_calendar may hold different addresses. It is not
75
+ # consulted once an address is named: pair the two with an `emails` entry
76
+ # instead, which states which work email the git identity belongs to.
77
+ # A malformed address is warned about and dropped; with none left, the source
78
+ # is skipped for that run and listed in failed_sources.
79
+ # user: your.personal@email.com
80
+ # user:
81
+ # - you@corp.com
82
+ # - 12345+you@users.noreply.github.com
83
+ #
84
+ # `emails` — translate a requested email -> git commit email(s). Applied on every
85
+ # path whenever that email is passed via --users / user_email. Add an entry for
86
+ # yourself too if your git identity differs from the work email you pass in.
87
+ # A malformed address is warned about and dropped; an entry left with none
88
+ # falls back to the requested email as-is.
89
+ # emails:
90
+ # alice@corp.com: alice.private@gmail.com
91
+ # bob@corp.com:
92
+ # - bob@corp.com
93
+ # - 67890+bob@users.noreply.github.com
94
+ google_calendar:
95
+ # Credentials come from GOOGLE_* environment variables, not from this file.
96
+ #
97
+ # Calendar to read meeting events from. One calendar only; a list is rejected.
98
+ # Default: "primary". That is each reported user's own main calendar.
99
+ # Set this and every reported user reads the same calendar instead. Each user is
100
+ # still authenticated as themselves, so Google checks their access.
101
+ # calendar_id: "primary"
102
+ #
103
+ # `emails` must give one address per person for this source. A list is rejected.
104
+ #
105
+ # Meeting time is filtered to the working_hours block below (if set): events fully
106
+ # outside work hours are dropped; partial overlaps are clamped.
107
+
108
+ # Optional: filter calculated time to business hours.
109
+ # Applies to Jira, ClickUp, Linear and Google Calendar meeting time.
110
+ # Omit this block to keep raw wall-clock time calculation.
111
+ # Note: start_hour must be earlier than end_hour (night shifts not supported); equal
112
+ # hours are rejected too. A shared block that breaks this is ignored with a warning,
113
+ # leaving time unfiltered; a person's block falls back to the shared one.
114
+ # working_hours:
115
+ # timezone: "Europe/Warsaw" # IANA timezone name
116
+ # start_hour: "09:00" # Work day start (HH:MM, must be quoted)
117
+ # end_hour: "17:00" # Work day end (HH:MM, must be quoted)
118
+ # work_days: [1, 2, 3, 4, 5] # Mon-Fri (0=Sun, 1=Mon, ..., 6=Sat)
119
+ # holidays_region: "pl" # Country code for public holiday exclusion (optional)
120
+ #
121
+ # # Optional: per-person overrides, keyed by the work email reports are requested for
122
+ # # (user_email: / user_emails:). A person inherits every key they leave out, and
123
+ # # anyone not listed here uses the block above unchanged.
124
+ # people:
125
+ # bob@corp.com:
126
+ # timezone: "America/New_York"
127
+ # holidays_region: "us"
128
+ # cara@corp.com:
129
+ # end_hour: "15:00"
130
+
131
+ # Optional: directory that saved markdown/html reports are written to.
132
+ # A relative path is resolved against the working directory.
133
+ # Default: ./snitcher_reports
134
+ # Overridden per call by output_dir:, and by output_path: for a single report.
135
+ # output_dir: "tmp/snitcher_reports"
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.2.0]
8
+
9
+ - First release published to RubyGems.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Visuality
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.