@beauraines/sprint-tracker 0.6.10 → 0.6.12
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.
- package/CHANGELOG.md +12 -1
- package/R/commitmentVarianceCli.R +206 -0
- package/cmds/stats.js +64 -0
- package/cmds/visualizations.js +1 -1
- package/package.json +1 -1
- package/sql/commitmentVariance.sql +52 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,12 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
### [0.6.
|
|
5
|
+
### [0.6.12](https://github.com/beauraines/sprint-tracker/compare/v0.6.9...v0.6.12) (2024-03-27)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* adds running statistics plot ([#61](https://github.com/beauraines/sprint-tracker/issues/61)) ([76c1f00](https://github.com/beauraines/sprint-tracker/commit/76c1f0032b96a7afc7923f5100dcf4ef2ea59d56))
|
|
6
11
|
|
|
7
12
|
|
|
8
13
|
### Bug Fixes
|
|
9
14
|
|
|
15
|
+
* comments out plot command and increments version number ([#62](https://github.com/beauraines/sprint-tracker/issues/62)) ([ee18e17](https://github.com/beauraines/sprint-tracker/commit/ee18e17e7327f890f353841caed46dd04cc8fbe7))
|
|
16
|
+
* **deps:** bump @json2csv/node from 7.0.1 to 7.0.4 ([#31](https://github.com/beauraines/sprint-tracker/issues/31)) ([68ed973](https://github.com/beauraines/sprint-tracker/commit/68ed973199df1a650ef7d677475bef1c23b144fd))
|
|
17
|
+
* **deps:** bump @json2csv/node from 7.0.4 to 7.0.5 ([91a5e3b](https://github.com/beauraines/sprint-tracker/commit/91a5e3bf32c24874ae4f6c7bc52a155e9da6b35a))
|
|
18
|
+
* **deps:** bump @json2csv/node from 7.0.5 to 7.0.6 ([#59](https://github.com/beauraines/sprint-tracker/issues/59)) ([1e2c7cb](https://github.com/beauraines/sprint-tracker/commit/1e2c7cb31af4074de33bd36c202dc82f6559eef8))
|
|
19
|
+
* **deps:** bump cli-markdown from 3.2.0 to 3.2.2 ([e178633](https://github.com/beauraines/sprint-tracker/commit/e178633fde4fea487e0fe82fb0d6eab6a29d9a33))
|
|
10
20
|
* **deps:** bump sqlite from 4.2.1 to 5.1.1 ([#28](https://github.com/beauraines/sprint-tracker/issues/28)) ([1fbc304](https://github.com/beauraines/sprint-tracker/commit/1fbc3049c9f218c5684699a5e320f34953d08a9f))
|
|
21
|
+
* **deps:** bump sqlite3 from 5.1.6 to 5.1.7 ([3b8b3fb](https://github.com/beauraines/sprint-tracker/commit/3b8b3fb82aa37f295408c6372527bcd26bcf7dcc))
|
|
11
22
|
|
|
12
23
|
### [0.6.9](https://github.com/beauraines/sprint-tracker/compare/v0.6.8...v0.6.9) (2023-12-16)
|
|
13
24
|
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
library(tidyverse)
|
|
2
|
+
library(zoo)
|
|
3
|
+
library(DBI)
|
|
4
|
+
library(RSQLite)
|
|
5
|
+
library(ggrepel)
|
|
6
|
+
|
|
7
|
+
args = commandArgs(trailingOnly=TRUE)
|
|
8
|
+
if (length(args)==0) {
|
|
9
|
+
stop("At least one argument must be supplied, the key", call.=FALSE)
|
|
10
|
+
}
|
|
11
|
+
project_id = if_else(is.na(args[1]),"4",args[1])
|
|
12
|
+
|
|
13
|
+
con <- dbConnect(RSQLite::SQLite(),"~/projects/sprint-tracker/tracker.db")
|
|
14
|
+
|
|
15
|
+
#TODO simplify this sql and build the data set in R, maybe
|
|
16
|
+
res <- dbSendQuery(con, str_c("WITH commitment as (
|
|
17
|
+
select
|
|
18
|
+
p.name,
|
|
19
|
+
s.id sprint_id,
|
|
20
|
+
s.sprint_name,
|
|
21
|
+
s.start_date,
|
|
22
|
+
s.end_date,
|
|
23
|
+
so.story_points,
|
|
24
|
+
o.name as outcome,
|
|
25
|
+
o.id
|
|
26
|
+
from
|
|
27
|
+
sprint_outcomes so
|
|
28
|
+
JOIN sprints s on sprint_id = s.id
|
|
29
|
+
JOIN projects p on project_id = p.id and p.id = ",project_id,
|
|
30
|
+
" JOIN outcomes o on outcome_id = o.id and outcome_id in (6) -- 1 Delivered, 6 Committment
|
|
31
|
+
),
|
|
32
|
+
completed as
|
|
33
|
+
(
|
|
34
|
+
select
|
|
35
|
+
p.name,
|
|
36
|
+
s.id sprint_id,
|
|
37
|
+
s.sprint_name,
|
|
38
|
+
s.start_date,
|
|
39
|
+
s.end_date,
|
|
40
|
+
so.story_points,
|
|
41
|
+
o.name as outcome,
|
|
42
|
+
o.id
|
|
43
|
+
from
|
|
44
|
+
sprint_outcomes so
|
|
45
|
+
JOIN sprints s on sprint_id = s.id
|
|
46
|
+
JOIN projects p on project_id = p.id and p.id = ",project_id,
|
|
47
|
+
" JOIN outcomes o on outcome_id = o.id and outcome_id in (1) -- 1 Delivered, 6 Committment
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
select
|
|
51
|
+
commitment.name,
|
|
52
|
+
commitment.sprint_id,
|
|
53
|
+
commitment.sprint_name,
|
|
54
|
+
commitment.start_date,
|
|
55
|
+
commitment.end_date,
|
|
56
|
+
commitment.story_points commitment,
|
|
57
|
+
completed.story_points completed,
|
|
58
|
+
(completed.story_points*1.0 - commitment.story_points*1.0)/commitment.story_points * 100.0 commitment_variance
|
|
59
|
+
from
|
|
60
|
+
commitment
|
|
61
|
+
LEFT JOIN completed on completed.sprint_id = commitment.sprint_id
|
|
62
|
+
where
|
|
63
|
+
1 =1
|
|
64
|
+
order by commitment.name,commitment.start_date
|
|
65
|
+
|
|
66
|
+
;
|
|
67
|
+
"))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# TODO query sqlite directly
|
|
71
|
+
sprintData <- dbFetch(res)
|
|
72
|
+
|
|
73
|
+
# Clear the result
|
|
74
|
+
dbClearResult(res)
|
|
75
|
+
|
|
76
|
+
# Disconnect from the database
|
|
77
|
+
dbDisconnect(con)
|
|
78
|
+
|
|
79
|
+
## Clean data
|
|
80
|
+
# Remove Foo and Abe's project
|
|
81
|
+
sprintData = sprintData %>%
|
|
82
|
+
filter(!name %in% c('Foo','Abe\'s projct'))
|
|
83
|
+
|
|
84
|
+
# How to deal with outliers
|
|
85
|
+
|
|
86
|
+
## Add numbering
|
|
87
|
+
sprintData = sprintData %>%
|
|
88
|
+
group_by(name) %>%
|
|
89
|
+
mutate(sprint_number = row_number()) %>%
|
|
90
|
+
add_count(name="project_sprint_count") %>%
|
|
91
|
+
mutate(project_percent_completed = sprint_number/project_sprint_count)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
## Add velocity
|
|
95
|
+
|
|
96
|
+
sprintData = sprintData %>%
|
|
97
|
+
group_by(name) %>%
|
|
98
|
+
mutate(velocity = cumsum(completed)/sprint_number)
|
|
99
|
+
|
|
100
|
+
## Add Completion Percentage
|
|
101
|
+
sprintData = sprintData %>%
|
|
102
|
+
group_by(name) %>%
|
|
103
|
+
mutate(commitment_percentage = completed/commitment)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
f_labels <- sprintData %>% summarise(
|
|
108
|
+
Velocity = sd(velocity, na.rm=TRUE) %>% formatC(digits = 3),
|
|
109
|
+
"Commitment Variance" = sd(commitment_variance, na.rm=TRUE) %>% formatC(digits = 3),
|
|
110
|
+
"Commitment Percentage" = sd(commitment_percentage, na.rm=TRUE) %>% formatC(digits = 3)
|
|
111
|
+
) %>%
|
|
112
|
+
select(!"name") %>%
|
|
113
|
+
pivot_longer(
|
|
114
|
+
cols = c("Velocity", "Commitment Variance", "Commitment Percentage"),
|
|
115
|
+
values_to = "label",
|
|
116
|
+
names_to = "measure" )
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# commitment_variance
|
|
120
|
+
# sprintData %>%
|
|
121
|
+
# ggplot(aes(x = sprint_number,
|
|
122
|
+
# y = commitment_variance,
|
|
123
|
+
# colour = name)) +
|
|
124
|
+
# geom_line() +
|
|
125
|
+
# geom_point()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# Sprint Velocity
|
|
130
|
+
# sprintData %>%
|
|
131
|
+
# ggplot(aes(x = sprint_number,
|
|
132
|
+
# y = velocity,
|
|
133
|
+
# colour = name)) +
|
|
134
|
+
# geom_line() +
|
|
135
|
+
# geom_point()
|
|
136
|
+
|
|
137
|
+
# Commitment Percentage
|
|
138
|
+
# sprintData %>%
|
|
139
|
+
# ggplot(aes(x = commitment_percentage,
|
|
140
|
+
# y = velocity,
|
|
141
|
+
# colour = name)) +
|
|
142
|
+
# geom_line() +
|
|
143
|
+
# geom_point()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
sprintDataPivot = sprintData %>%
|
|
147
|
+
select(!c(completed,commitment,sprint_id,project_sprint_count,project_percent_completed)) %>%
|
|
148
|
+
pivot_longer(
|
|
149
|
+
c(velocity,commitment_percentage,commitment_variance),
|
|
150
|
+
names_to = "measure",
|
|
151
|
+
values_to = "value"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
projectName = unique(sprintDataPivot$name)
|
|
155
|
+
|
|
156
|
+
plot <- sprintDataPivot %>%
|
|
157
|
+
ggplot(aes(x = reorder(str_wrap(sprint_name,15),sprint_number),
|
|
158
|
+
y = value
|
|
159
|
+
)) +
|
|
160
|
+
geom_line(group=1,color = "#b9b9b9") +
|
|
161
|
+
geom_point(color = "#b9b9b9") +
|
|
162
|
+
# Add point values
|
|
163
|
+
geom_text_repel(
|
|
164
|
+
aes(label=round(value,2)),
|
|
165
|
+
direction = "y",
|
|
166
|
+
family = "roboto",
|
|
167
|
+
size = 10 * 5/14 * 0.8) +
|
|
168
|
+
# plot labels
|
|
169
|
+
labs(title=str_c(projectName,"Sprint Statistics", sep =" "),
|
|
170
|
+
x ="",
|
|
171
|
+
y = "") +
|
|
172
|
+
#themes
|
|
173
|
+
theme(
|
|
174
|
+
plot.title = element_text(family = "roboto"),
|
|
175
|
+
axis.title.x = element_text(family = "roboto"),
|
|
176
|
+
axis.text.x = element_text(angle = 45, vjust = 1, hjust=1),
|
|
177
|
+
axis.title.y = element_text(family = "roboto"),
|
|
178
|
+
panel.grid.major.y = element_line(colour = "#D9D9D9"),
|
|
179
|
+
panel.grid.minor.y = element_line(colour = "#D9D9D9"),
|
|
180
|
+
panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
|
|
181
|
+
# background color
|
|
182
|
+
panel.background = element_rect(fill = "#D9D9D920", colour = NA),
|
|
183
|
+
legend.position = "bottom",
|
|
184
|
+
plot.background = element_rect(colour = "#D9D9D9", fill=NA)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
plot <- plot + facet_wrap(
|
|
188
|
+
vars(str_to_title(sub("_"," ",measure))),
|
|
189
|
+
ncol = 1,
|
|
190
|
+
scales = "free_y"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
plot <- plot +
|
|
194
|
+
geom_label(
|
|
195
|
+
x = 1,
|
|
196
|
+
y = Inf,
|
|
197
|
+
aes(label = str_c("St Dev = ",label), hjust = "left", vjust = 1.3),
|
|
198
|
+
data = f_labels
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# plot
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
ggsave(str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),plot=plot,bg="white", width = 2882, height = 1700, units = "px")
|
|
205
|
+
|
|
206
|
+
print(str_c("Saving to ",str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),sep = " "))
|
package/cmds/stats.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { database: db } = require('helpers')
|
|
4
|
+
const { prompt } = require('../utils/input.js')
|
|
5
|
+
const {readConfig} = require('helpers').config
|
|
6
|
+
const exec = require('child_process').exec;
|
|
7
|
+
const process = require('process');
|
|
8
|
+
|
|
9
|
+
const command = 'stats'
|
|
10
|
+
const desc = 'Creates sprint statistics (Commitment variance, Commitment Percentage and Velocity ) with R. Requires a local R install'
|
|
11
|
+
const builder = {}
|
|
12
|
+
|
|
13
|
+
const handler = async function () {
|
|
14
|
+
// Get Data from Database and write to file
|
|
15
|
+
console.log('Getting data')
|
|
16
|
+
|
|
17
|
+
const filename = 'sprintTracker.json'
|
|
18
|
+
const config = await readConfig(filename)
|
|
19
|
+
const database = config.database
|
|
20
|
+
|
|
21
|
+
// list projects
|
|
22
|
+
|
|
23
|
+
let statement = 'select * from projects;';
|
|
24
|
+
|
|
25
|
+
let projects = await db.query(database,statement)
|
|
26
|
+
|
|
27
|
+
for (const project of projects) {
|
|
28
|
+
console.log(project.id, project.name)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Select the project
|
|
32
|
+
|
|
33
|
+
// Select the project
|
|
34
|
+
let project_id
|
|
35
|
+
|
|
36
|
+
let text = 'Enter the project id: '
|
|
37
|
+
while (!project_id) {
|
|
38
|
+
project_id = prompt(text)
|
|
39
|
+
|
|
40
|
+
// validate the response
|
|
41
|
+
if (!projects.find(x => (x.id == project_id))) {
|
|
42
|
+
console.error('Invalid project id')
|
|
43
|
+
project_id = null
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log('Making statistics visualizations')
|
|
48
|
+
const cmd = `Rscript ${__dirname}/../R/commitmentVarianceCli.R ${project_id}`
|
|
49
|
+
exec(cmd, function(err, stdout, stderr) {
|
|
50
|
+
if (err) {
|
|
51
|
+
console.log(stderr);
|
|
52
|
+
console.log(err.message)
|
|
53
|
+
process.exit(err.code)
|
|
54
|
+
}
|
|
55
|
+
console.log(stdout);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
command,
|
|
61
|
+
desc,
|
|
62
|
+
builder,
|
|
63
|
+
handler
|
|
64
|
+
}
|
package/cmds/visualizations.js
CHANGED
|
@@ -11,7 +11,7 @@ const path = require('path');
|
|
|
11
11
|
const process = require('process');
|
|
12
12
|
|
|
13
13
|
const command = 'visualizations'
|
|
14
|
-
const desc = 'Creates
|
|
14
|
+
const desc = 'Creates sprint visualizations with R. Requires a local R install'
|
|
15
15
|
const builder = {}
|
|
16
16
|
|
|
17
17
|
const handler = async function () {
|
package/package.json
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
WITH commitment as
|
|
2
|
+
|
|
3
|
+
(
|
|
4
|
+
select
|
|
5
|
+
p.name,
|
|
6
|
+
s.id sprint_id,
|
|
7
|
+
s.sprint_name,
|
|
8
|
+
s.start_date,
|
|
9
|
+
s.end_date,
|
|
10
|
+
so.story_points,
|
|
11
|
+
o.name as outcome,
|
|
12
|
+
o.id
|
|
13
|
+
from
|
|
14
|
+
sprint_outcomes so
|
|
15
|
+
JOIN sprints s on sprint_id = s.id
|
|
16
|
+
JOIN projects p on project_id = p.id --and p.id = 11
|
|
17
|
+
JOIN outcomes o on outcome_id = o.id and outcome_id in (6) -- 1 Delivered, 6 Committment
|
|
18
|
+
),
|
|
19
|
+
|
|
20
|
+
completed as
|
|
21
|
+
(
|
|
22
|
+
select
|
|
23
|
+
p.name,
|
|
24
|
+
s.id sprint_id,
|
|
25
|
+
s.sprint_name,
|
|
26
|
+
s.start_date,
|
|
27
|
+
s.end_date,
|
|
28
|
+
so.story_points,
|
|
29
|
+
o.name as outcome,
|
|
30
|
+
o.id
|
|
31
|
+
from
|
|
32
|
+
sprint_outcomes so
|
|
33
|
+
JOIN sprints s on sprint_id = s.id
|
|
34
|
+
JOIN projects p on project_id = p.id --and p.id = 11
|
|
35
|
+
JOIN outcomes o on outcome_id = o.id and outcome_id in (1) -- 1 Delivered, 6 Committment
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
select
|
|
39
|
+
commitment.name,
|
|
40
|
+
commitment.sprint_id,
|
|
41
|
+
commitment.sprint_name,
|
|
42
|
+
commitment.start_date,
|
|
43
|
+
commitment.end_date,
|
|
44
|
+
commitment.story_points commitment,
|
|
45
|
+
completed.story_points completed,
|
|
46
|
+
(completed.story_points*1.0 - commitment.story_points*1.0)/commitment.story_points * 100.0 commitment_variance
|
|
47
|
+
from
|
|
48
|
+
commitment
|
|
49
|
+
LEFT JOIN completed on completed.sprint_id = commitment.sprint_id
|
|
50
|
+
where
|
|
51
|
+
commitment.name in ('ALPR Data Enhancement','ECOM Enhancements')
|
|
52
|
+
order by commitment.name,commitment.sprint_name
|