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.
- checksums.yaml +7 -0
- data/.snitcher.yml.example +135 -0
- data/CHANGELOG.md +9 -0
- data/LICENSE +21 -0
- data/README.md +685 -0
- data/lib/snitcher/anomaly.rb +24 -0
- data/lib/snitcher/anomaly_context.rb +76 -0
- data/lib/snitcher/anomaly_detector.rb +32 -0
- data/lib/snitcher/anomaly_rules/base.rb +29 -0
- data/lib/snitcher/anomaly_rules/commits_without_closed_tickets.rb +22 -0
- data/lib/snitcher/anomaly_rules/estimate_overrun.rb +37 -0
- data/lib/snitcher/anomaly_rules/excessive_meeting_time.rb +43 -0
- data/lib/snitcher/anomaly_rules/inactive_working_days.rb +32 -0
- data/lib/snitcher/anomaly_rules/time_above_availability.rb +27 -0
- data/lib/snitcher/client.rb +177 -0
- data/lib/snitcher/configuration.rb +123 -0
- data/lib/snitcher/holiday_region_resolver.rb +123 -0
- data/lib/snitcher/jql_validator.rb +44 -0
- data/lib/snitcher/meetings_aggregator.rb +38 -0
- data/lib/snitcher/orchestrator.rb +227 -0
- data/lib/snitcher/presenters/html.rb +87 -0
- data/lib/snitcher/presenters/markdown.rb +140 -0
- data/lib/snitcher/presenters/presenter.rb +90 -0
- data/lib/snitcher/report.rb +112 -0
- data/lib/snitcher/report_service.rb +128 -0
- data/lib/snitcher/report_writer.rb +74 -0
- data/lib/snitcher/sources/clickup/archived_lists.rb +174 -0
- data/lib/snitcher/sources/clickup/working_hours_filter.rb +88 -0
- data/lib/snitcher/sources/clickup.rb +467 -0
- data/lib/snitcher/sources/git/command_runner.rb +198 -0
- data/lib/snitcher/sources/git.rb +347 -0
- data/lib/snitcher/sources/google_calendar.rb +328 -0
- data/lib/snitcher/sources/jira/client.rb +346 -0
- data/lib/snitcher/sources/jira/status_categories.rb +60 -0
- data/lib/snitcher/sources/jira.rb +523 -0
- data/lib/snitcher/sources/linear.rb +257 -0
- data/lib/snitcher/sources/source.rb +140 -0
- data/lib/snitcher/templates/report.html.erb +564 -0
- data/lib/snitcher/templates/snitcher-logo.png +0 -0
- data/lib/snitcher/time_formatter.rb +27 -0
- data/lib/snitcher/validators.rb +59 -0
- data/lib/snitcher/version.rb +5 -0
- data/lib/snitcher/work_item.rb +75 -0
- data/lib/snitcher/working_hours_calculator.rb +205 -0
- data/lib/snitcher/working_hours_config.rb +208 -0
- data/lib/snitcher.rb +39 -0
- 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.
|