@beauraines/sprint-tracker 0.6.1

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 (53) hide show
  1. package/.eslintrc.json +16 -0
  2. package/.github/dependabot.yml +21 -0
  3. package/CHANGELOG.md +52 -0
  4. package/R/HeloSprintBurndown.R +138 -0
  5. package/R/ProjectHealth.R +109 -0
  6. package/R/backlogByTeam.R +52 -0
  7. package/R/backlogHealth.R +163 -0
  8. package/R/burndDownChart.R +144 -0
  9. package/R/carryOverAdjustedVelocity.R +154 -0
  10. package/R/featureTeamBacklog.R +73 -0
  11. package/R/projectHealth.Rmd +111 -0
  12. package/R/sprintOutcomes.R +142 -0
  13. package/R/sprintOutcomesCli.R +103 -0
  14. package/R/sprintOutcomesFeatureTeam.R +143 -0
  15. package/R/timeInCodeReview.R +157 -0
  16. package/README.md +181 -0
  17. package/cli.js +55 -0
  18. package/cmds/addOutcomes.js +98 -0
  19. package/cmds/addProject.js +53 -0
  20. package/cmds/addSprint.js +117 -0
  21. package/cmds/config.js +33 -0
  22. package/cmds/getSprintDetails.js +86 -0
  23. package/cmds/visualizations.js +116 -0
  24. package/docker-compose.yml +11 -0
  25. package/migrations/20230222011333-create-health-table.sql +10 -0
  26. package/migrations/20230222011334-outcomes.sql +42 -0
  27. package/migrations/20231206093700-seed-outcomes-table.sql +9 -0
  28. package/migrations.js +20 -0
  29. package/package.json +50 -0
  30. package/scripts/generateBacklogByTeam.sh +20 -0
  31. package/scripts/generateBacklogHealth.sh +12 -0
  32. package/scripts/generateChart.sh +7 -0
  33. package/scripts/generateFeatureTeamBacklog.sh +16 -0
  34. package/scripts/generateSprintOutcomePlot.sh +12 -0
  35. package/scripts/sprintOutcomes.sh +29 -0
  36. package/sql/bugsOpenedDuringSprint.sql +14 -0
  37. package/sql/bugsOpenedDuringSprintFeature.sql +14 -0
  38. package/sql/capacityAdjustedVelocity.sql +48 -0
  39. package/sql/carryOver.sql +33 -0
  40. package/sql/commitment.sql +30 -0
  41. package/sql/commitmentMet.sql +60 -0
  42. package/sql/completed.sql +40 -0
  43. package/sql/descoped.sql +21 -0
  44. package/sql/pullForward.sql +19 -0
  45. package/sql/pullForwardFeature.sql +10 -0
  46. package/sql/sprintOutcomes.sql +25 -0
  47. package/sql/sprint_outcomes.sql +23 -0
  48. package/src/addOutcomes.js +94 -0
  49. package/src/addSprint.js +108 -0
  50. package/src/getSprintDetails.js +88 -0
  51. package/utils/display.js +68 -0
  52. package/utils/input.js +24 -0
  53. package/utils/readConfig.js +74 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "env": {
3
+ "browser": true,
4
+ "commonjs": true,
5
+ "es2021": true,
6
+ "node": true
7
+ },
8
+ "extends": "eslint:recommended",
9
+ "overrides": [
10
+ ],
11
+ "parserOptions": {
12
+ "ecmaVersion": "latest"
13
+ },
14
+ "rules": {
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "npm" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
12
+ day: "friday"
13
+ commit-message:
14
+ prefix: fix
15
+ prefix-development: chore
16
+ include: scope
17
+ groups:
18
+ dev-dependencies:
19
+ dependency-type: "development"
20
+ patterns:
21
+ - "*"
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
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
+
5
+ ### [0.6.1](https://bitbucket.org/beauraines/sprint-tracker/compare/v0.6.0...v0.6.1) (2023-03-25)
6
+
7
+
8
+ ### Features
9
+
10
+ * adds cli command to create tracker database ([d17d671](https://bitbucket.org/beauraines/sprint-tracker/commit/d17d6715ac2206476adf15c754069fd4c606c113))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * adds await to config reader ([4e7d3d1](https://bitbucket.org/beauraines/sprint-tracker/commit/4e7d3d1c6bd703257f958e3fdb17929ac579fcc7))
16
+ * **migrations:** allows to run on pre-existing database ([d0bef24](https://bitbucket.org/beauraines/sprint-tracker/commit/d0bef242ee3890d2a14cc933564c329ece231a2d))
17
+ * updates database migration commands ([f0a2307](https://bitbucket.org/beauraines/sprint-tracker/commit/f0a230735e836b54362f01123a914ce9047c2c98))
18
+ * updates script name ([a93c724](https://bitbucket.org/beauraines/sprint-tracker/commit/a93c7247d7483b8f87a378dd75aee198c1f18563))
19
+
20
+ ## [0.6.0](https://bitbucket.org/beauraines/sprint-tracker/compare/v0.5.2...v0.6.0) (2023-03-25)
21
+
22
+
23
+ ### ⚠ BREAKING CHANGES
24
+
25
+ * removes `recordSprintOutcomes` command
26
+ * now a configuration file is required `~/sprintTracker.json` with the full path to the database
27
+
28
+ ```
29
+ {
30
+ "database":"/Users/beauraines/projects/sprint-tracker/tracker.db"
31
+ }
32
+ ```
33
+
34
+ ### Features
35
+
36
+ * adds command line support and sub commands ([0c897e1](https://bitbucket.org/beauraines/sprint-tracker/commit/0c897e1986a02281863dfbfd65cf0615d05874f3))
37
+ * adds sprintTracker command to global install ([54256cc](https://bitbucket.org/beauraines/sprint-tracker/commit/54256cc3be8ca1323a40c8a79b2483d09add8026))
38
+ * database is specified in config ([c33b916](https://bitbucket.org/beauraines/sprint-tracker/commit/c33b9169b87302b80aed3753b846b347db9f1f1c))
39
+
40
+ ### [0.5.2](https://bitbucket.org/beauraines/sprint-tracker/compare/v0.5.1...v0.5.2) (2023-03-08)
41
+
42
+
43
+ ### Features
44
+
45
+ * adds script to generate outcome plot ([8d53548](https://bitbucket.org/beauraines/sprint-tracker/commit/8d535488eee52087b736bfbdf020d57aa43cbc37))
46
+
47
+ ### 0.5.1 (2023-03-06)
48
+
49
+
50
+ ### Bug Fixes
51
+
52
+ * update dependencies ([394cfa3](https://bitbucket.org/beauraines/sprint-tracker/commit/394cfa38c025265d3c925bca6785c754a3e56f2a))
@@ -0,0 +1,138 @@
1
+ library(ggplot2)
2
+ library(tidyverse)
3
+ library(lubridate)
4
+ library(DBI)
5
+ library(RSQLite)
6
+ con <- dbConnect(RSQLite::SQLite(),"~/BurnDownStatus.db")
7
+
8
+
9
+
10
+
11
+ res <- dbSendQuery(con, "select
12
+ p.project_key,
13
+ p.name project,
14
+ ifnull(e.epic_name,b.epic) team,
15
+ b.date,
16
+ b.issue_status,
17
+ sum(b.issue_count) issue_count,
18
+ sum(b.estimate) estimate
19
+ from burndown b
20
+ LEFT join epics e on e.epic_key = b.epic
21
+ LEFT join projects p on b.project = p.project_key
22
+ WHERE b.project = 'HELO'
23
+ and b.date >= '2023-05-16'
24
+ group by
25
+ p.project_key,
26
+ p.name,
27
+ b.epic,
28
+ b.date,
29
+ b.issue_status
30
+ order by date desc;")
31
+
32
+ queryResponse = dbFetch(res)
33
+
34
+ burndownData = queryResponse %>%
35
+ tibble() %>%
36
+ mutate(date = as_datetime(date)) %>%
37
+ rename(issues = issue_count, Status = issue_status ) %>%
38
+ filter(!Status %in% c("Duplicate","Wont Do","As Designed","Cant Repro")) %>%
39
+ filter(!team %in% c('Data Science','Product')) %>%
40
+ # Transform other statuses
41
+ mutate( Status =
42
+ case_when(
43
+ Status == "Defining" ~ "Backlog",
44
+ Status == "Triaged" ~ "Backlog",
45
+ Status == "New" ~ "Backlog",
46
+ Status == "Team Review" ~ "Active",
47
+ Status == "In QA" ~ "QA Review",
48
+ Status == "In UAT" ~ "QA Review",
49
+ TRUE ~ as.character(Status))) %>%
50
+ relocate(date) %>%
51
+ arrange(date,team) %>%
52
+ group_by(date,project,project_key,team,Status) %>%
53
+ summarize(issues = sum(issues),estimate = sum(estimate)) %>%
54
+ ungroup()
55
+
56
+ burndownData = burndownData %>%
57
+ ## all dates need to have values, missing values to 0
58
+ pivot_wider(names_from=Status, values_from = issues, values_fill = 0, id_cols = !estimate) %>%
59
+ pivot_longer(cols = !c(date,project,project_key,team), names_to = "Status", values_to = "issues")
60
+
61
+
62
+ # Clear the result
63
+ dbClearResult(res)
64
+
65
+ # Disconnect from the database
66
+ dbDisconnect(con)
67
+
68
+ lapply(sort(unique(burndownData$team)), function(Team) {
69
+
70
+ # Team = 'Frontend'
71
+
72
+ burndown = burndownData %>%
73
+ # filter(Status != 'Closed') %>%
74
+ group_by(date,project,project_key,team) %>%
75
+ summarize(
76
+ closed_issues = sum(issues[Status != 'Closed']),
77
+ qa_issues = sum(issues[!Status %in% c('Closed',"QA Review")])
78
+ ) %>%
79
+ filter(team == Team)
80
+
81
+ plotTitle = str_c(unique(burndown$team),"Sprint Burndown",sep=" ")
82
+ print(str_c("Plotting",plotTitle, sep=" "))
83
+
84
+ sprintStart = floor_date(min(burndown$date),"day")
85
+ startingIssueCount = burndown %>% filter(date == min(burndown$date)) %>% pull(closed_issues)
86
+
87
+ sprintEnd=sprintStart + days(12) # Days after first sprint snapshot. This should change in the long run
88
+ sprintDuration = as.integer(sprintEnd) - as.integer(sprintStart)
89
+ slope = -1 * startingIssueCount/sprintDuration
90
+ intercept = startingIssueCount - slope*as.integer(sprintStart)
91
+
92
+ burndown %>%
93
+ ggplot(aes(x=date)) +
94
+ geom_line(aes(y=closed_issues,color="red")) +
95
+ geom_line(aes(y=qa_issues,color="blue")) +
96
+ geom_abline(intercept = intercept, slope = slope, color = "black") +
97
+ scale_x_datetime(date_labels = "%d-%b",date_breaks = "1 day") +
98
+ labs(title = plotTitle,
99
+ subtitle = "red = issues closed, blue = issues to QA",
100
+ x = "Date",
101
+ y = "Issue Count",
102
+ alt = paste("Team burn down",
103
+ "displaying the idealized burndown",
104
+ sep = " ")) +
105
+ expand_limits(x=c(sprintStart,sprintEnd),y=0) +
106
+ theme(
107
+ plot.title = element_text(family = "roboto"),
108
+ axis.title.x = element_text(family = "roboto"),
109
+ axis.title.y = element_text(family = "roboto"),
110
+ panel.grid.major.y = element_line(colour = "#D9D9D9"), panel.grid.minor.y = element_line(colour = "#D9D9D9"),
111
+ panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
112
+ # background color
113
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
114
+ legend.position = "bottom",
115
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
116
+ ) +
117
+ scale_y_continuous(breaks = scales::pretty_breaks())
118
+
119
+ print(str_c("Saving",plotTitle,sep = " "))
120
+ ggsave(str_c("~/projects/sprint-tracker/","Helo-Sprint-Burndown-",Team,".png"),bg="white", width = 2882, height = 1700, units = "px")
121
+ })
122
+
123
+
124
+ ## This tries to facet_wrap the plots but it's not working
125
+ # burndownData %>%
126
+ # filter(Status != 'Closed') %>%
127
+ # group_by(date,project,project_key,team) %>%
128
+ # summarize(issues = sum(issues),estimate = sum(estimate)) %>%
129
+ # ggplot(aes(x=date)) +
130
+ # geom_line(aes(y=issues,color=team)) +
131
+ # geom_abline(intercept = burndownData %>% filter(date == sprintStart) %>% pull(issues) - slope*as.integer(min(burndownData$date)),
132
+ # slope = slope,
133
+ # color = "black") +
134
+ # scale_x_date(date_labels = "%d-%b",date_breaks = "1 day") +
135
+ # expand_limits(x=c(min(burndownData$date),min(burndownData$date) + 12),y=0) +
136
+ # facet_wrap(~team,ncol = 2)
137
+
138
+
@@ -0,0 +1,109 @@
1
+ library(ggplot2)
2
+ library(tidyverse)
3
+
4
+ library(DBI)
5
+ library(RSQLite)
6
+ con <- dbConnect(RSQLite::SQLite(), "~/projects/sprint-tracker/tracker.db")
7
+
8
+
9
+
10
+
11
+ res <- dbSendQuery(con, "select *
12
+ from health
13
+ where
14
+ project = 'ALPR Data Enhancements'
15
+ -- project = 'ACDC'
16
+ Order by date desc;")
17
+
18
+
19
+ project_health = dbFetch(res) %>%
20
+ tibble() %>%
21
+ mutate(date = as.Date(date,"%Y-%m-%d"),
22
+ closed_count = total_count - open_count,
23
+ closed_percentage = (total_count - open_count) / total_count,
24
+ unestimated_percentage = unestimated_count /open_count,
25
+ # aim_unestimated_percentage = (unestimated_count -26) /(open_count -26)
26
+ )
27
+
28
+ project_health = project_health%>%
29
+ pivot_longer(cols=contains(c("count","percentage")),names_to = "measure",values_to = "count")
30
+
31
+
32
+ # Clear the result
33
+ dbClearResult(res)
34
+
35
+ # Disconnect from the database
36
+ dbDisconnect(con)
37
+
38
+
39
+ ## Issue Counts
40
+
41
+ plotTitle = paste(project_health%>%pull(project)%>%unique(),"Issue Counts")
42
+ issuePlot = project_health %>%
43
+ filter(!measure %in% c("unestimated_percentage","closed_percentage","blocked_count","bug_count")) %>%
44
+ ggplot() +
45
+ geom_line(aes(x=date,y=count,group=measure,color=measure)) +
46
+ # geom_line(data=project_health,aes(x=date,y=count)) +
47
+ geom_hline(yintercept = 26) + # Issues to roll over to CDCE project = ACDC and labels in (move-to-cdce) ORDER BY cf[12111] ASC
48
+ labs(title = plotTitle,
49
+ x = "Date",
50
+ y = "Issue Count",
51
+ caption = str_wrap("The horizontal line indicates the number of issues that will be rolled over to the CDCE team on 10 March at the end of the AIM SOW",width=100),
52
+ alt = "") +
53
+ # scale_colour_manual(values = statusColors,guide_legend(title=legendTitle)) +
54
+ # scale_fill_manual(values = statusFills, guide_legend(title=legendTitle)) +
55
+ scale_x_date(date_labels = "%d-%b",date_breaks = "1 week") +
56
+ expand_limits(y=0) +
57
+ theme(
58
+ plot.title = element_text(family = "roboto"),
59
+ axis.title.x = element_text(family = "roboto"),
60
+ axis.title.y = element_text(family = "roboto"),
61
+ panel.grid.major.y = element_line(colour = "#D9D9D9"), panel.grid.minor.y = element_line(colour = "#D9D9D9"),
62
+ panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
63
+ # background color
64
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
65
+ legend.position = "bottom",
66
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
67
+ ) +
68
+ scale_y_continuous(breaks = scales::pretty_breaks())
69
+ filename = str_c("~/projects/sprint-tracker/",str_remove_all(plotTitle," "),".png")
70
+ print(str_c("Saving",plotTitle,"to",filename,sep = " "))
71
+ ggsave(filename,plot=issuePlot,bg="white")
72
+
73
+ ## Issue Counts
74
+
75
+ plotTitle = paste(project_health%>%pull(project)%>%unique(),"Project Health")
76
+ countPlot = project_health %>%
77
+ filter(measure %in% c("unestimated_percentage","closed_percentage")) %>%
78
+ ggplot() +
79
+ geom_line(aes(x=date,y=count,group=measure,color=measure)) +
80
+ # geom_line(data=project_health,aes(x=date,y=count)) +
81
+ labs(title = plotTitle,
82
+ x = "Date",
83
+ y = "Percentage",
84
+ caption = str_wrap("This plot includes issues from non-AIM teams, including 26 issues that will be rolled over to the CDCE team at the end of our contract",
85
+ width=100),
86
+ alt = "") +
87
+ # scale_colour_manual(values = statusColors,guide_legend(title=legendTitle)) +
88
+ # scale_fill_manual(values = statusFills, guide_legend(title=legendTitle)) +
89
+ scale_x_date(date_labels = "%d-%b",date_breaks = "1 week") +
90
+ # expand_limits(y=0) +
91
+ theme(
92
+ plot.title = element_text(family = "roboto"),
93
+ axis.title.x = element_text(family = "roboto"),
94
+ axis.title.y = element_text(family = "roboto"),
95
+ panel.grid.major.y = element_line(colour = "#D9D9D9"), panel.grid.minor.y = element_line(colour = "#D9D9D9"),
96
+ panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
97
+ # background color
98
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
99
+ legend.position = "bottom",
100
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
101
+ ) +
102
+ # scale_y_continuous(breaks = scales::pretty_breaks()) +
103
+ ylim(0,1) +
104
+ facet_wrap(~measure,
105
+ nrow = 2)
106
+ filename = str_c("~/projects/sprint-tracker/",str_remove_all(plotTitle," "),".png")
107
+ print(str_c("Saving",plotTitle,"to",filename,sep = " "))
108
+ ggsave(filename,plot=countPlot,bg="white")
109
+
@@ -0,0 +1,52 @@
1
+ library(ggplot2)
2
+ library(tidyverse)
3
+ library(lubridate)
4
+
5
+ #az boards query --organization https://dev.azure.com/teamsi --id b18a81c9-3e3a-4dc6-87ef-140caf5bcb6a | jq -r '[.[]| {team:.fields."System.AreaPath",type:.fields."System.WorkItemType",id,estimate: .fields."Microsoft.VSTS.Scheduling.StoryPoints" }]' | json2csv -o ~/projects/backlog.csv
6
+
7
+ backlog = read_csv('~/projects/backlog.csv')
8
+
9
+ data = backlog %>%
10
+ mutate(
11
+ estimate = replace_na(estimate,0),
12
+ team = str_remove(team,"The Helo Project\\\\Solution Team(\\\\)"),
13
+ team = str_remove(team,"The Helo Project\\\\")
14
+ ) %>%
15
+ group_by(team,type) %>%
16
+ summarise(count = n()) %>%
17
+ mutate(total = sum(count))
18
+
19
+ p = ggplot(data,aes(x=reorder(team,total),y=count, fill=type, color = type)) +
20
+ geom_col() +
21
+ coord_flip() +
22
+ scale_fill_manual(values=c("#31313180",
23
+ "#d61c1c80",
24
+ "#2e509680")) +
25
+ scale_color_manual(values=c("#313131",
26
+ "#d61c1c",
27
+ "#2e5096")) +
28
+ labs(title = "Backlog Work Items by Team",
29
+ subtitle = "Work-items in a ready to work state, including Stories, Analyses, and Bugs.\nThis includes work-items both assigned and not assigned to a sprint, including the current sprint.",
30
+ x = "",
31
+ y = "Issue Count",
32
+ alt = paste("QA issue burn up chart",
33
+ sep = " "),
34
+ caption = Sys.Date(),
35
+ fill = 'Work Item Type',
36
+ color = 'Work Item Type') +
37
+ theme(
38
+ plot.title = element_text(family = "roboto"),
39
+ axis.title.x = element_text(family = "roboto"),
40
+ axis.title.y = element_text(family = "roboto"),
41
+ panel.grid.major.x = element_line(colour = "#D9D9D9"), panel.grid.minor.x = element_line(colour = "#D9D9D9"),
42
+ panel.grid.major.y = element_blank(), panel.grid.minor.y = element_blank(),
43
+ # background color
44
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
45
+ legend.position = "bottom",
46
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA)
47
+ )
48
+
49
+ FILENAME = str_c("~/projects/sprint-tracker/","backlog_by_team",".png")
50
+ ggsave(FILENAME,plot=p,bg="white", width = 2882, height = 1700, units = "px")
51
+ print(str_c("Saving to ",FILENAME),sep = " ")
52
+
@@ -0,0 +1,163 @@
1
+ library(ggplot2)
2
+ library(tidyverse)
3
+
4
+ library(DBI)
5
+ library(RSQLite)
6
+ con <- dbConnect(RSQLite::SQLite(),"~/projects/sprint-tracker/tracker.db")
7
+
8
+ res <- dbSendQuery(con, "
9
+ SELECT
10
+ bh.id,
11
+ p.name,
12
+ bh.date,
13
+ bh.health_type,
14
+ bh.backlog_count,
15
+ bh.unhealthy_count
16
+ FROM backlog_health bh
17
+ JOIN
18
+ projects p ON p.id = bh.project_id;
19
+ ")
20
+
21
+ backlogData = dbFetch(res) %>%
22
+ tibble() %>%
23
+ select(-id) %>%
24
+ mutate(
25
+ date = lubridate::ymd(date),
26
+ healthy_count = backlog_count - unhealthy_count)
27
+
28
+ # pivot_longer(cols=c(qa_review_count,qa_validated_count),values_to="count",names_to="status") %>%
29
+ # Coalesce NA to zero
30
+ # mutate(count = replace_na(count,0),date = lubridate::ymd(date))
31
+
32
+
33
+ # Clear the result
34
+ dbClearResult(res)
35
+
36
+ # Disconnect from the database
37
+ dbDisconnect(con)
38
+
39
+
40
+ statusColors = c("backlog_count" = "#000000", "healthy_count" = "#03AC13")
41
+ statusFills = c("backlog_count" = "#00000020", "healthy_count" = "#03AC1380")
42
+
43
+
44
+
45
+ p<-backlogData %>%
46
+ pivot_longer(cols=c(backlog_count,unhealthy_count,healthy_count),values_to = "count", names_to = "health_state") %>%
47
+ filter(health_type == 'workable backlog') %>%
48
+ filter(!health_state == 'unhealthy_count') %>%
49
+ ggplot(aes(x=date,
50
+ y=count
51
+ ,
52
+ group=health_state,
53
+ color=health_state,
54
+ fill=health_state
55
+ )) +
56
+ # geom_point() + geom_line() +
57
+ geom_area(linewidth=2,position="identity") +
58
+ geom_label(data = backlogData %>%
59
+ pivot_longer(cols=c(backlog_count,unhealthy_count,healthy_count),values_to = "count", names_to = "health_state") %>%
60
+ filter(health_type == 'workable backlog') %>%
61
+ filter(health_state == "healthy_count")%>%
62
+ tail(n=1),
63
+ mapping = aes(y=count,label=count),
64
+ nudge_y = 1.1,
65
+ nudge_x = 2.2) +
66
+ geom_label(data = backlogData %>%
67
+ pivot_longer(cols=c(backlog_count,unhealthy_count,healthy_count),values_to = "count", names_to = "health_state") %>%
68
+ filter(health_type == 'workable backlog') %>%
69
+ filter(health_state == "backlog_count")%>%
70
+ tail(n=1),
71
+ mapping = aes(y=count,label=count),
72
+ nudge_y = 1.1,
73
+ nudge_x = 2.2) +
74
+ scale_color_manual(values = statusColors,guide_legend(title="Status")) +
75
+ scale_fill_manual(values = statusFills,guide_legend(title="Status")) +
76
+ labs(title = "Backlog Health",
77
+ subtitle = "Workable items with acceptance criteria text",
78
+ x = "Date",
79
+ y = "Issue Count",
80
+ alt = paste("Line chart of workable backlog items",
81
+ sep = " "),
82
+ caption = Sys.Date()) +
83
+ scale_x_date(date_labels = "%d-%b",date_breaks = "1 week") +
84
+ theme(
85
+ plot.title = element_text(family = "roboto"),
86
+ axis.title.x = element_text(family = "roboto"),
87
+ axis.title.y = element_text(family = "roboto"),
88
+ axis.text.x = element_text(angle = 45, vjust = 1, hjust=1),
89
+ # Grid
90
+ panel.grid.major.y = element_line(colour = "#D9D9D9"),
91
+ panel.grid.minor.y = element_line(colour = "#D9D9D9"),
92
+ panel.grid.major.x = element_line(colour = "#D9D9D9"),
93
+ panel.grid.minor.x = element_blank(),
94
+ # background color
95
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
96
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA),
97
+ # Move legend
98
+ legend.position = "bottom"
99
+ )
100
+
101
+ ggsave(str_c("~/projects/ado-utilities/","backlog_health_ac",".png"),plot=p,bg="white", width = 2882, height = 1700, units = "px")
102
+
103
+
104
+ p<-backlogData %>%
105
+ pivot_longer(cols=c(backlog_count,unhealthy_count,healthy_count),values_to = "count", names_to = "health_state") %>%
106
+ filter(health_type == 'backlog health') %>%
107
+ filter(!health_state == 'unhealthy_count') %>%
108
+ ggplot(aes(x=date,
109
+ y=count
110
+ ,
111
+ group=health_state,
112
+ color=health_state,
113
+ fill=health_state
114
+ )) +
115
+ # geom_point() + geom_line() +
116
+ geom_area(linewidth=2,position="identity") +
117
+ geom_label(data = backlogData %>%
118
+ pivot_longer(cols=c(backlog_count,unhealthy_count,healthy_count),values_to = "count", names_to = "health_state") %>%
119
+ filter(health_type == 'backlog health') %>%
120
+ filter(health_state == "healthy_count")%>%
121
+ tail(n=1),
122
+ mapping = aes(y=count,label=count),
123
+ nudge_y = 1.1,
124
+ nudge_x = 2.2) +
125
+ geom_label(data = backlogData %>%
126
+ pivot_longer(cols=c(backlog_count,unhealthy_count,healthy_count),values_to = "count", names_to = "health_state") %>%
127
+ filter(health_type == 'backlog health') %>%
128
+ filter(health_state == "backlog_count")%>%
129
+ tail(n=1),
130
+ mapping = aes(y=count,label=count),
131
+ nudge_y = 1.1,
132
+ nudge_x = 2.2) +
133
+ scale_color_manual(values = statusColors,guide_legend(title="Status")) +
134
+ scale_fill_manual(values = statusFills,guide_legend(title="Status")) +
135
+ labs(title = "Backlog Health",
136
+ subtitle = "Backlog items (Story,Analysis) in a ready to work state. Prior to 14 June 2023, bugs were included in the data.",
137
+ x = "Date",
138
+ y = "Issue Count",
139
+ alt = paste("QA issue burn up chart",
140
+ sep = " "),
141
+ caption = Sys.Date()) +
142
+ scale_x_date(date_labels = "%d-%b",date_breaks = "1 week") +
143
+ theme(
144
+ plot.title = element_text(family = "roboto"),
145
+ axis.title.x = element_text(family = "roboto"),
146
+ axis.title.y = element_text(family = "roboto"),
147
+ axis.text.x = element_text(angle = 45, vjust = 1, hjust=1),
148
+ # Grid
149
+ panel.grid.major.y = element_line(colour = "#D9D9D9"),
150
+ panel.grid.minor.y = element_line(colour = "#D9D9D9"),
151
+ panel.grid.major.x = element_line(colour = "#D9D9D9"),
152
+ panel.grid.minor.x = element_blank(),
153
+ # background color
154
+ panel.background = element_rect(fill = "#D9D9D920", colour = NA),
155
+ plot.background = element_rect(colour = "#D9D9D9", fill=NA),
156
+ # Move legend
157
+ legend.position = "bottom"
158
+ )
159
+
160
+ FILENAME = str_c("~/projects/ado-utilities/","backlog_health",".png")
161
+ ggsave(FILENAME,plot=p,bg="white", width = 2882, height = 1700, units = "px")
162
+ print(str_c("Saving to ",FILENAME),sep = " ")
163
+