@beauraines/sprint-tracker 0.6.14 → 0.6.15

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 CHANGED
@@ -2,6 +2,13 @@
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.15](https://github.com/beauraines/sprint-tracker/compare/v0.6.14...v0.6.15) (2024-05-17)
6
+
7
+
8
+ ### Features
9
+
10
+ * combines stats and visualization plots ([#71](https://github.com/beauraines/sprint-tracker/issues/71)) ([34f1237](https://github.com/beauraines/sprint-tracker/commit/34f1237d4cbcaaa80c97392e9f494369377980ba))
11
+
5
12
  ### [0.6.14](https://github.com/beauraines/sprint-tracker/compare/v0.6.12...v0.6.14) (2024-05-06)
6
13
 
7
14
 
@@ -0,0 +1,345 @@
1
+ library(tidyverse)
2
+ library(zoo)
3
+ library(DBI)
4
+ library(RSQLite)
5
+ library(ggrepel)
6
+ library(patchwork)
7
+
8
+ args = commandArgs(trailingOnly=TRUE)
9
+ if (length(args)==0) {
10
+ stop("At least one argument must be supplied, the key", call.=FALSE)
11
+ }
12
+ project_id = if_else(is.na(args[1]),"4",args[1])
13
+
14
+ con <- dbConnect(RSQLite::SQLite(),"~/projects/sprint-tracker/tracker.db")
15
+
16
+ #TODO simplify this sql and build the data set in R, maybe
17
+ res <- dbSendQuery(con, str_c("WITH commitment as (
18
+ select
19
+ p.name,
20
+ s.id sprint_id,
21
+ s.sprint_name,
22
+ s.start_date,
23
+ s.end_date,
24
+ so.story_points,
25
+ o.name as outcome,
26
+ o.id
27
+ from
28
+ sprint_outcomes so
29
+ JOIN sprints s on sprint_id = s.id
30
+ JOIN projects p on project_id = p.id and p.id = ",project_id,
31
+ " JOIN outcomes o on outcome_id = o.id and outcome_id in (6) -- 1 Delivered, 6 Committment
32
+ ),
33
+ completed as
34
+ (
35
+ select
36
+ p.name,
37
+ s.id sprint_id,
38
+ s.sprint_name,
39
+ s.start_date,
40
+ s.end_date,
41
+ so.story_points,
42
+ o.name as outcome,
43
+ o.id
44
+ from
45
+ sprint_outcomes so
46
+ JOIN sprints s on sprint_id = s.id
47
+ JOIN projects p on project_id = p.id and p.id = ",project_id,
48
+ " JOIN outcomes o on outcome_id = o.id and outcome_id in (1) -- 1 Delivered, 6 Committment
49
+ )
50
+
51
+ select
52
+ commitment.name,
53
+ commitment.sprint_id,
54
+ commitment.sprint_name,
55
+ commitment.start_date,
56
+ commitment.end_date,
57
+ commitment.story_points commitment,
58
+ completed.story_points completed
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 Percentage" = sd(commitment_percentage, na.rm=TRUE) %>% formatC(digits = 3)
110
+ ) %>%
111
+ select(!"name") %>%
112
+ pivot_longer(
113
+ cols = c("Velocity", "Commitment Percentage"),
114
+ values_to = "label",
115
+ names_to = "measure" )
116
+
117
+
118
+ sprintDataPivot = sprintData %>%
119
+ select(!c(completed,commitment,sprint_id,project_sprint_count,project_percent_completed)) %>%
120
+ pivot_longer(
121
+ c(velocity,commitment_percentage),
122
+ names_to = "measure",
123
+ values_to = "value"
124
+ )
125
+
126
+ projectName = unique(sprintDataPivot$name)
127
+
128
+ velocity <- sprintDataPivot %>%
129
+ filter(measure == 'velocity') %>%
130
+ ggplot(aes(x = reorder(str_wrap(sprint_name,15),sprint_number),
131
+ y = value
132
+ )) +
133
+ geom_line(group=1,color = "#b9b9b9") +
134
+ geom_point(color = "#b9b9b9") +
135
+ # Add point values
136
+ geom_text_repel(
137
+ aes(label=round(value,2)),
138
+ direction = "y",
139
+ family = "roboto",
140
+ size = 10 * 5/14 * 0.8) +
141
+ # plot labels
142
+ labs(title=str_c(projectName,"Velocity", sep =" "),
143
+ x ="",
144
+ y = "") +
145
+ #themes
146
+ theme(
147
+ plot.title = element_text(family = "roboto"),
148
+ # NO x-axis labels
149
+ axis.title.x = element_blank(),
150
+ axis.text.x = element_blank(),
151
+ axis.title.y = element_text(family = "roboto"),
152
+ panel.grid.major.y = element_line(colour = "#D9D9D9"),
153
+ panel.grid.minor.y = element_line(colour = "#D9D9D9"),
154
+ panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
155
+ # background color
156
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
157
+ legend.position = "bottom",
158
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
159
+ )
160
+
161
+ commitmentPercentage <- sprintDataPivot %>%
162
+ filter(measure == 'commitment_percentage') %>%
163
+ ggplot(aes(x = reorder(str_wrap(sprint_name,15),sprint_number),
164
+ y = value
165
+ )) +
166
+ geom_hline(yintercept = 1, color = "green") +
167
+ geom_hline(yintercept = .8, color = "yellow") +
168
+ geom_hline(yintercept = .6, color = "red") +
169
+ geom_line(group=1,color = "#b9b9b9") +
170
+ geom_point(color = "#b9b9b9") +
171
+ # Add point values
172
+ geom_text_repel(
173
+ aes(label=scales::label_percent()(round(value,2))),
174
+ direction = "y",
175
+ family = "roboto",
176
+ size = 10 * 5/14 * 0.8) +
177
+ # plot labels
178
+ labs(title=str_c(projectName,"Commitment Percentage", sep =" "),
179
+ x ="",
180
+ y = "") +
181
+ scale_y_continuous (labels = scales::percent) +
182
+ #themes
183
+ theme(
184
+ plot.title = element_text(family = "roboto"),
185
+ # has x-axis labels because this is the bottom plot
186
+ # TODO are these axis labels actually needed with the columns below
187
+ # axis.title.x = element_text(family = "roboto"),
188
+ # axis.text.x = element_text(angle = 45, vjust = 1, hjust=1),
189
+ axis.title.x = element_blank(),
190
+ axis.text.x = element_blank(),
191
+ axis.title.y = element_text(family = "roboto"),
192
+ panel.grid.major.y = element_line(colour = "#D9D9D9"),
193
+ panel.grid.minor.y = element_line(colour = "#D9D9D9"),
194
+ panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
195
+ # background color
196
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
197
+ legend.position = "bottom",
198
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
199
+ )
200
+
201
+
202
+
203
+
204
+ # Add StdDeviation to each plot
205
+ velocity <- velocity +
206
+ geom_label(
207
+ x = 1,
208
+ y = Inf,
209
+ aes(label = str_c("St Dev = ",label), hjust = "left", vjust = 1.3),
210
+ data = f_labels %>% filter(measure == 'Velocity')
211
+ )
212
+
213
+ commitmentPercentage <- commitmentPercentage +
214
+ geom_label(
215
+ x = 1,
216
+ y = Inf,
217
+ aes(label = str_c("St Dev = ",label), hjust = "left", vjust = 1.3),
218
+ data = f_labels %>% filter(measure == 'Commitment Percentage')
219
+ )
220
+
221
+
222
+
223
+ # Add shading to commitment percentage plots
224
+ commitmentPercentage <- commitmentPercentage +
225
+ annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=-Inf,ymax=0.6,fill=alpha(c("red"),0.1)) +
226
+ annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=0.6,ymax=0.8,fill=alpha("yellow",0.1)) +
227
+ annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=0.8,ymax=Inf,fill=alpha(c("green"),0.1))
228
+
229
+
230
+
231
+ ### Generate Sprint Outcomes
232
+
233
+ # TODO - pull in the SQL here
234
+ outcomes = read_csv(str_c(Sys.getenv("HOME"),"/","outcomes.csv"))
235
+
236
+ outcomes <- outcomes %>%
237
+ tibble() %>%
238
+ filter(story_points != 0) %>%
239
+ mutate(
240
+ end_date = as.Date(end_date)
241
+ )
242
+
243
+ # compute velocity statistics
244
+
245
+ entire_project_velocity = (outcomes %>%
246
+ filter(outcome == 'B-Delivered' ) %>%
247
+ summarize( average_velocity = mean(story_points)))$average_velocity
248
+
249
+ average_velocity = (outcomes %>%
250
+ filter(outcome == 'B-Delivered') %>%
251
+ filter(!sprint_name %in% c('Accessibility Improvement 0','Accessibility Improvements 1')) %>%
252
+ summarize( average_velocity = mean(story_points)))$average_velocity
253
+
254
+ # Compute 95% band velocity
255
+
256
+ outcomeColors = c("A-Commitment" = "#0B4F6C",
257
+ "Carryover" = "#D34E24",
258
+ "Carryover - External" = "#d3248d",
259
+ "Descoped" ="#A39BA8",
260
+ "Unplanned - Bug" ="#F28123",
261
+ "Unplanned - Story" = "#F7F052",
262
+ "B-Delivered" ="#00A878")
263
+ outcomeFills = c("A-Commitment" = "#0B4F6C",
264
+ "Carryover" = "#D34E24",
265
+ "Carryover - External" = "#d3248d",
266
+ "Descoped" ="#A39BA8",
267
+ "Unplanned - Bug" ="#F28123",
268
+ "Unplanned - Story" = "#F7F052",
269
+ "B-Delivered" ="#00A878")
270
+
271
+ chartTitle = str_c("Sprint Outcomes - ",unique(outcomes$project_name))
272
+
273
+ outcomePlot <-ggplot(outcomes,
274
+ aes(fill=outcome,
275
+ y=story_points,
276
+ # x=end_date
277
+ #x = str_wrap(sprint_name,15)
278
+ x = reorder(str_wrap(sprint_name,15),end_date)
279
+ )
280
+ )+
281
+ geom_bar(position="dodge", stat="identity",color = "black") +
282
+ # add bar labels
283
+ geom_text(data = outcomes %>% mutate(story_points = na_if(story_points,0)),
284
+ aes(label=story_points, y = story_points + .5),
285
+ position = position_dodge(0.9)) +
286
+ # trendline
287
+ geom_smooth(aes(#x=factor(end_date),
288
+ x=factor(reorder(str_wrap(sprint_name,15),end_date)),
289
+ y=story_points,group=outcome),
290
+ data = outcomes%>%filter(outcome=="B-Delivered"),
291
+ #method = "lm", # no method = curved line
292
+ se=FALSE,
293
+ show.legend = FALSE,
294
+ linetype = "dashed",
295
+ color = "#00A878") +
296
+ # TODO better position this annotation
297
+ annotate(geom="text",
298
+ x=length(unique(outcomes$sprint_name))+.25,
299
+ y=average_velocity + 1.5,
300
+ label="Trend Line") +
301
+ # average velocity line
302
+ geom_hline(yintercept=average_velocity,linetype = "dotted", color = "#00A878") +
303
+ annotate(geom="text", x=.75, y=average_velocity + 1.5, label="Average\nVelocity") +
304
+ # plot labels
305
+ labs(title=chartTitle,
306
+ # subtitle = 'Excluding the Data Science, Product Ownership and QA Teams',
307
+ x ="",
308
+ y = "Story Points",
309
+ fill='Outcomes') +
310
+ #colors
311
+ scale_colour_manual(values = outcomeColors) +
312
+ scale_fill_manual(values = outcomeFills) +
313
+ #themes
314
+ theme(
315
+ plot.title = element_text(family = "roboto"),
316
+ axis.title.x = element_text(family = "roboto"),
317
+ axis.text.x = element_text(angle = 45, vjust = 1, hjust=1),
318
+ axis.title.y = element_text(family = "roboto"),
319
+ panel.grid.major.y = element_line(colour = "#D9D9D9"), panel.grid.minor.y = element_line(colour = "#D9D9D9"),
320
+ panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
321
+ # background color
322
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
323
+ legend.position = "bottom",
324
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
325
+ )
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+ statsPlot <- velocity /
334
+ commitmentPercentage /
335
+ outcomePlot
336
+
337
+
338
+
339
+
340
+ # plot
341
+
342
+
343
+ ggsave(str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),plot=statsPlot,bg="white", width = 2882, height = 1700, units = "px")
344
+
345
+ print(str_c("Saving to ",str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),sep = " "))
@@ -55,8 +55,7 @@ select
55
55
  commitment.start_date,
56
56
  commitment.end_date,
57
57
  commitment.story_points commitment,
58
- completed.story_points completed,
59
- (completed.story_points*1.0 - commitment.story_points*1.0)/commitment.story_points * 100.0 commitment_variance
58
+ completed.story_points completed
60
59
  from
61
60
  commitment
62
61
  LEFT JOIN completed on completed.sprint_id = commitment.sprint_id
@@ -107,12 +106,11 @@ sprintData = sprintData %>%
107
106
 
108
107
  f_labels <- sprintData %>% summarise(
109
108
  Velocity = sd(velocity, na.rm=TRUE) %>% formatC(digits = 3),
110
- "Commitment Variance" = sd(commitment_variance, na.rm=TRUE) %>% formatC(digits = 3),
111
109
  "Commitment Percentage" = sd(commitment_percentage, na.rm=TRUE) %>% formatC(digits = 3)
112
110
  ) %>%
113
111
  select(!"name") %>%
114
112
  pivot_longer(
115
- cols = c("Velocity", "Commitment Variance", "Commitment Percentage"),
113
+ cols = c("Velocity", "Commitment Percentage"),
116
114
  values_to = "label",
117
115
  names_to = "measure" )
118
116
 
@@ -120,7 +118,7 @@ f_labels <- sprintData %>% summarise(
120
118
  sprintDataPivot = sprintData %>%
121
119
  select(!c(completed,commitment,sprint_id,project_sprint_count,project_percent_completed)) %>%
122
120
  pivot_longer(
123
- c(velocity,commitment_percentage,commitment_variance),
121
+ c(velocity,commitment_percentage),
124
122
  names_to = "measure",
125
123
  values_to = "value"
126
124
  )
@@ -184,42 +182,7 @@ commitmentPercentage <- sprintDataPivot %>%
184
182
  #themes
185
183
  theme(
186
184
  plot.title = element_text(family = "roboto"),
187
- # NO x-axis labels
188
- axis.title.x = element_blank(),
189
- axis.text.x = element_blank(),
190
- axis.title.y = element_text(family = "roboto"),
191
- panel.grid.major.y = element_line(colour = "#D9D9D9"),
192
- panel.grid.minor.y = element_line(colour = "#D9D9D9"),
193
- panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
194
- # background color
195
- panel.background = element_rect(fill = "#D9D9D920", colour = NA),
196
- legend.position = "bottom",
197
- plot.background = element_rect(colour = "#D9D9D9", fill=NA)
198
- )
199
-
200
- commitmentVariance <- sprintDataPivot %>%
201
- filter(measure == 'commitment_variance') %>%
202
- ggplot(aes(x = reorder(str_wrap(sprint_name,15),sprint_number),
203
- y = value
204
- )) +
205
- geom_hline(yintercept = 1, color = "green") +
206
- geom_hline(yintercept = -20, color = "yellow") +
207
- geom_hline(yintercept = -60, color = "red") +
208
- geom_line(group=1,color = "#b9b9b9") +
209
- geom_point(color = "#b9b9b9") +
210
- # Add point values
211
- geom_text_repel(
212
- aes(label=round(value,2)),
213
- direction = "y",
214
- family = "roboto",
215
- size = 10 * 5/14 * 0.8) +
216
- # plot labels
217
- labs(title=str_c(projectName,"Commitment Variance", sep =" "),
218
- x ="",
219
- y = "") +
220
- #themes
221
- theme(
222
- plot.title = element_text(family = "roboto"),
185
+ # has x-axis labels because this is the bottom plot
223
186
  axis.title.x = element_text(family = "roboto"),
224
187
  axis.text.x = element_text(angle = 45, vjust = 1, hjust=1),
225
188
  axis.title.y = element_text(family = "roboto"),
@@ -233,6 +196,8 @@ commitmentVariance <- sprintDataPivot %>%
233
196
  )
234
197
 
235
198
 
199
+
200
+
236
201
  # Add StdDeviation to each plot
237
202
  velocity <- velocity +
238
203
  geom_label(
@@ -250,29 +215,19 @@ commitmentPercentage <- commitmentPercentage +
250
215
  data = f_labels %>% filter(measure == 'Commitment Percentage')
251
216
  )
252
217
 
253
- commitmentVariance <- commitmentVariance +
254
- geom_label(
255
- x = 1,
256
- y = Inf,
257
- aes(label = str_c("St Dev = ",label), hjust = "left", vjust = 1.3),
258
- data = f_labels %>% filter(measure == 'Commitment Variance')
259
- )
260
218
 
261
- # Add shading to commitment variance and commitment percentage plots
219
+
220
+ # Add shading to commitment percentage plots
262
221
  commitmentPercentage <- commitmentPercentage +
263
222
  annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=-Inf,ymax=0.6,fill=alpha(c("red"),0.1)) +
264
223
  annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=0.6,ymax=0.8,fill=alpha("yellow",0.1)) +
265
224
  annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=0.8,ymax=Inf,fill=alpha(c("green"),0.1))
266
225
 
267
- commitmentVariance <- commitmentVariance +
268
- annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=-Inf,ymax=-60,fill=alpha(c("red"),0.1)) +
269
- annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=-60,ymax=-20,fill=alpha("yellow",0.1)) +
270
- annotate(geom ="rect",xmin=-Inf,xmax=Inf,ymin=-20,ymax=Inf,fill=alpha(c("green"),0.1))
271
226
 
272
227
 
273
- plot <- velocity /
274
- commitmentPercentage /
275
- commitmentVariance
228
+
229
+ statsPlot <- velocity /
230
+ commitmentPercentage
276
231
 
277
232
 
278
233
 
@@ -280,6 +235,6 @@ commitmentVariance
280
235
  # plot
281
236
 
282
237
 
283
- ggsave(str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),plot=plot,bg="white", width = 2882, height = 1700, units = "px")
238
+ ggsave(str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),plot=statsPlot,bg="white", width = 2882, height = 1700, units = "px")
284
239
 
285
240
  print(str_c("Saving to ",str_c(Sys.getenv("HOME"),"/",str_replace(projectName," ",""),"SprintStats.png"),sep = " "))
package/cmds/stats.js CHANGED
@@ -45,7 +45,7 @@ const handler = async function () {
45
45
  }
46
46
 
47
47
  console.log('Making statistics visualizations')
48
- const cmd = `Rscript ${__dirname}/../R/commitmentVarianceCli.R ${project_id}`
48
+ const cmd = `Rscript ${__dirname}/../R/combinedStats.R ${project_id}`
49
49
  exec(cmd, function(err, stdout, stderr) {
50
50
  if (err) {
51
51
  console.log(stderr);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beauraines/sprint-tracker",
3
- "version": "0.6.14",
3
+ "version": "0.6.15",
4
4
  "description": "Database and R visualizations to track sprint performance",
5
5
  "main": "cli.js",
6
6
  "bin": {