Skip to content

Instantly share code, notes, and snippets.

@apexskier
Last active January 17, 2023 23:56
Show Gist options
  • Save apexskier/1da717b234fea455077fd7d36ebb12b4 to your computer and use it in GitHub Desktop.
Save apexskier/1da717b234fea455077fd7d36ebb12b4 to your computer and use it in GitHub Desktop.
jira-graphs

A set of utilities I use to generate visual graphs of JIRA progress. Since our Jira is behind SSO, I can't easily query the API directly, so I run this in chrome, after authenticating. It generates a graph in graphviz dot format, which I can then run through http://www.webgraphviz.com/ or using the CLI tool.

These are pretty specific to different projects and workflows, so modify them as you see fit.

// NOTE: this uses let so it can be rerun in dev tools
let issues = (
await (
await fetch(`/rest/api/2/search?expand=&jql=issuetype in standardIssueTypes() AND "Epic Link" = ${issueKey}`)
).json()
).issues
.map((i) => ({
key: i.key,
summary: i.fields.summary,
status: i.fields.status.name,
links: i.fields.issuelinks
.filter((l) => l.outwardIssue && l.type.outward == "blocks")
.map((l) => ({
key: l.outwardIssue.key,
type: l.type.outward,
summary: l.outwardIssue.status,
status: l.outwardIssue.fields.status.name,
})),
}))
.filter((i) => i.status !== "Duplicate");
let maxes = [];
let mins = [];
for (let issue of issues) {
if (!issues.some((i) => i.links.some((l) => l.key == issue.key))) {
mins.push(issue.key);
} else if (issue.links.length == 0) {
maxes.push(issue.key);
}
}
let outwardIssues = [];
for (const issue of [].concat(...issues.map((i) => i.links))) {
if (
outwardIssues.find((i) => i.key === issue.key) ||
issues.find((i) => i.key === issue.key)
) {
continue;
}
outwardIssues.push(issue);
}
let statusColors = {
Triage: "ghostwhite",
Open: "lightgrey",
"In Progress": "skyblue",
"Review": "skyblue",
"Sign off": "skyblue",
Closed: "palegreen",
};
// dashed are outside of this story
console.log(
`digraph G {
node [style="dashed,filled", fillcolor=ghostwhite]
` +
outwardIssues
.map(
(i) =>
` "${i.key}" [style="dashed,filled", fillcolor=${
statusColors[i.status] || "ghostwhite"
}] // ${i.status}`
)
.join("\n") +
"\n\n" +
issues
.map(
(i) =>
` "${i.key}" [style=filled, fillcolor=${
statusColors[i.status] || "ghostwhite"
}] // ${i.status}`
)
.join("\n") +
"\n\n" +
issues
.map((i) => i.links.map((l) => ` "${i.key}" -> "${l.key}"`).join("\n"))
.filter((i) => i)
.join("\n") +
`
{ rank=min; ${mins.map((m) => `"${m}"; `).join("")}}
{ rank=max; ${maxes.map((m) => `"${m}"; `).join("")}}
}`
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment