Utils function to compute technical debt metrics and display them on the support of your choice.
npm install --save-dev techdebt
This package is nothing more than an aggregation of helpers to get, save and display metrics.
It helps you to easily write a small script that computes metrics representing your technical debt. A good idea would be to run this script during continuous integration so that it updates a technical debt dashboard or Slack channel.
const techdebt = require('techdebt')
const slackClient = require('techdebt/clients/slack')
const fsHelper = require('techdebt/helpers/fs')
slackClient.initialize({
hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
channel: '#techdebt',
username: 'Techdebt bot'
})
techdebt.run([
{
get: () => fsHelper.getRegexMatches('src', /todo(.*)/gi),
format: (matches) => ({
title: 'Todos in code',
text: matches.length > 0 : matches.join('\n') : 'No todos in code ☀️',
color: matches.length > 0 : 'warning' : 'good'
})
},
])
.then(formatedMetrics => slackClient.post('Techdebt report', formatedMetrics))
.then(() => {
return process.exit()
})
.catch(error => {
console.error(error)
return process.exit(1)
})
Sometimes it's useful to get the history of a metric and display it as a graph. To save a metric you can use any API that you like. The simplest API I found is datadog that allows to save metrics and take a snapshot of a graph of the metric.
const techdebt = require('techdebt')
const slackClient = require('techdebt/clients/slack')
const fsHelper = require('techdebt/helpers/fs')
slackClient.initialize({
hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
channel: '#techdebt',
username: 'Techdebt bot'
})
datadogClient.initialize({
api_key: 'xxx',
app_key: 'xxx'
})
techdebt.run([
{
get: () => {
const count = fsHelper.countRegex('src', /todo/gi)
return count
},
save: (count) => datadogClient.post('techdebt.todos', count),
format: (count) => datadogClient.get('techdebt.todos', 3600 * 24 * 30)
.then(snapshotUrl => ({ text: 'Todos in code', image_url: snapshotUrl }))
}
])
.then(formatedMetrics => slackClient.post('Techdebt report', formatedMetrics))
.then(() => {
return process.exit()
})
.catch(error => {
console.error(error)
return process.exit(1)
})
Takes an array of metrics and return a promise of formated metrics.
Example:
const techdebt = require('techdebt')
techdebt.run(metrics)
.then(formatedMetrics => {
// do whatever you want with formated metrics
})
{
get: Function
save: Function
format: Function
}
A function that fetch the metric value. It returns a value of any type (you'll have to handle the value).
It can return a value or the promise of a value.
Example:
get: () => fsHelper.countRegex('src', /todo/gi)
A function that save the value on a third party tool such as Datadog, Google Spreadsheet etc.
If it returns a promise, the format function will wait for this promise to be resolved before execution.
Example:
const save = (metricValue) => datadogClient.post('techdebt.my_metric', metricValue)
A function that format the value as expected.
Example:
format = (metricValue) => ({
title: 'Todos count in code',
text: metricValue
})
Initialize the client with options
Example:
const slackClient = require('techdebt/clients/slack')
slackClient.initialize({
hookUrl: 'https://hooks.slack.com/services/xx/xx/xx', // required
channel: '#techdebt', // required
username: 'Techdebt bot' // optional
})
Post attachments to Slack.
Using this client requires to install dogapi package:
npm install --save-dev dogapi
const datadogClient = require('techdebt/clients/datadog')
datadogClient.initialize({
api_key: 'xxx', //required
app_key: 'xxx' // required
})
const codecovClient = require('techdebt/clients/codecov')
codecovClient.initialize({
accessToken: 'xxx', //required
repo: 'owner/repo', // required
branch: 'xxx' // required
})
Return a promise on the last code coverage ratio.
codecovClient.get()
.then(({ timestamp, ratio }) => {
// ratio between 0 and 100
})
Post a metric value that will be saved to datadog and wait for the metric to be fetchable (datadog has a delay in serving posted metrics).
The timestamp attribute is optional (default is now)
It returns a promise that resolves when the metric is saved.
Get the snapshot of a graph of a metric.
It returns a promise of the URL of the snapshot image.
missing a client? Trello, Google sheet ? Please write an issue
This helper requires to install npm-check
npm install --save-dev npm-check
This helper allow you to know which of your dependencies are unused or need upgrades
type can be one of major
, minor
, unused
, upToDate
.
It returns a promise of the list of packages corresponding to the type.
Returns a predefined Slack attachment format
Example:
const slackClient = require('techdebt/clients/slack')
const packages = require('techdebt/helpers/packages')
const techdebt = require('techdebt')
slackClient.initialize({
hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
channel: '#techdebt',
username: 'Techdebt bot'
})
techdebt.run([
{
get: () => packages.get('major'),
format: (items) => packages.slackFormat('major', items)
},
{
get: () => packages.get('minor'),
format: (items) => packages.slackFormat('minor', items)
},
{
get: () => packages.get('unused'),
format: (items) => packages.slackFormat('unused', items)
},
{
get: () => packages.get('upToDate'),
format: (items) => packages.slackFormat('upToDate', items)
}
])
.then(formatedMetrics => {
return slackClient.post('Techdebt report', formatedMetrics)
})
.then(() => {
return process.exit()
})
.catch(error => {
console.error(error)
return process.exit(1)
})
A librairy of helper functions to analyse source files.
Get the recursive list of files in a directory.
Example:
fsHelper.readRecursively('src')
Sum the lines of files in a directory (recursively). You can specify an extension in the options. The returned value is a promise of the line count.
Example:
fsHelper.countLines('src', { extension: 'js' }).then(lineCount => ...)
Sum the number of occurence if a regex in a directory (recursively). You can specify an extension in the options. The returned value is a promise of the count.
Example:
fsHelper.countRegex('src', /todo/gi, { extension: 'js' }).then(count => ...)
const slackClient = require('techdebt/clients/slack')
const datadogClient = require('techdebt/clients/datadog')
const fsHelper = require('techdebt/helpers/fs')
const techdebt = require('techdebt')
slackClient.initialize({
hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
channel: '#techdebt',
username: 'Techdebt bot'
})
datadogClient.initialize({
api_key: 'xxx',
app_key: 'xxx'
})
techdebt.run([
{
get: () => {
const count = fsHelper.countRegex('src', /todo/gi)
return count
},
save: (value) => datadogClient.post('techdebt.todos', value),
format: (count) => datadogClient.get('techdebt.todos', 3600 * 24 * 30).then(snapshotUrl => ({
text: 'Todos in code',
image_url: snapshotUrl
}))
},
{
get: () => fsHelper.getRegexMatches('src', /todo(.*)/gi),
format: (matches) => ({
title: 'Todos in code',
text: matches.join('\n'),
color: 'warning'
})
}
])
.then(formatedMetrics => {
return slackClient.post('Techdebt report', formatedMetrics)
})
.then(() => {
return process.exit()
})
.catch(error => {
console.error(error)
return process.exit(1)
})
Get the matches of a regex in a directory (recursively). You can specify an extension in the options. The returned value is a promise of the matches.
Example:
fsHelper.getRegexMatches('src', /todo(.*)/gi, { extension: 'js' }).then(matches => ...)