Skip to content

Commit

Permalink
Merge pull request #2 from jpmoura/release/v0.1.0
Browse files Browse the repository at this point in the history
Release/v0.1.0
  • Loading branch information
jpmoura authored Mar 29, 2021
2 parents 280bd19 + 380c879 commit f88fe0e
Show file tree
Hide file tree
Showing 32 changed files with 1,415 additions and 146 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PAT="azureDevOpsPersonalAccessToken"
PROJECT_NAME="Project"
TEAM_NAME="Project Product Team"
ORGANIZATION_NAME="ACME"
DEVOPS_USER="a.devops.user.with.access@user.com"
DEVOPS_PASSWORD="the.password"
SMTP_USER="user@host.com"
SMTP_PASSWORD="super.secret.password"
SMTP_HOST="smtp.host.com"
SMTP_PORT=587
EMAIL_RECIPIENTS="stackholer@acme.com,another.stackholder@acme.com"
EMAIL_CARBON_COPY_RECIPIENTS="team.member@team.com,another.team.member@team.com"
DEBUG=false
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules
lib
dist
dist
34 changes: 17 additions & 17 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"jest"
],
"extends": [
"airbnb-typescript/base",
"plugin:jest/all"
],
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
"class-methods-use-this": 0
}
}
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"jest"
],
"extends": [
"airbnb-typescript/base",
"plugin:jest/all"
],
"parserOptions": {
"project": "tsconfig.json"
},
"rules": {
"max-len": 0
}
}
52 changes: 11 additions & 41 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
Expand All @@ -20,12 +16,11 @@ lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
Expand All @@ -44,21 +39,12 @@ jspm_packages/
# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

Expand All @@ -70,35 +56,19 @@ typings/

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
# next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/
# Idea config folder
/.idea

# FuseBox cache
.fusebox/
# SonarLint folder
/.scannerwork/

# DynamoDB Local files
.dynamodb/
# SonarScanner properties
/sonar-project.properties

# TernJS port file
.tern-port
/dist
*.db
report.html
18 changes: 18 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Debug",
"skipFiles": [
"<node_internals>/**"
],
"preLaunchTask": "tsc: build - tsconfig.json",
"program": "${workspaceFolder}\\src\\index.ts",
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
}
]
}
16 changes: 16 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript",
"typescript",
"typescriptreact"
],
"eslint.alwaysShowStatus": true,
"eslint.packageManager": "yarn",
"cSpell.words": [
"burndown",
"tslog"
],
}
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,71 @@
# azure-devops-sprint-daily-report
An automatic application that sends daily reports based on Azure DevOps information
# 📄 azure-devops-sprint-daily-report
This is an automatic application that sends daily reports based on Azure DevOps information built with Node.js using TypeScript. It consumed the DevOps API to gather all relevant information about the team's current iteration, format as HTML email and send to a list of stakeholders.

The main goal is to schedule this application to execute daily in a server so every business day the report about the iteration status will be sended to a list of stakeholders, freeing the dev team time to focus on what really matters.

## 1. Project structure 🏠

This project uses clean code approach with repository pattern. The structure is the following:

```
|-\assets
|----\images
|----\templates
|-\src
|----\domain
|--------\model
|--------\use-case
|----\infra
|--------\repository
|----\use-case
```

### 1.1 assets directory
Contains all images and [Eta](https://github.com/eta-dev/eta) templates in respective folders.

The project templates are in brazilian portuguese but feel free to adapt the templates according your needs.

### 1.2 src directory
Contains all source files separated by responsibilities like `domain`, `infra` and `use-case`

1. `domain`: contains all interfaces used across the application
2. `infra`: contains all data repositories at this point
3. `use-case`: contains all business logic like building the e-mail HTML, fetching the current iteration data and sending e-mail

## 2. Environment Configuration 🔧

A example of a `.env` should be:

```
PAT="azureDevOpsPersonalAccessToken"
PROJECT_NAME="Project"
TEAM_NAME="Project Product Team"
ORGANIZATION_NAME="ACME"
DEVOPS_USER="a.devops.user.with.access@user.com"
DEVOPS_PASSWORD="the.password"
SMTP_USER="user@host.com"
SMTP_PASSWORD="super.secret.password"
SMTP_HOST="smtp.host.com"
SMTP_PORT=587
EMAIL_RECIPIENTS="stackholer@acme.com,another.stackholder@acme.com"
EMAIL_CARBON_COPY_RECIPIENTS="team.member@team.com,another.team.member@team.com"
DEBUG=false
```

Remember to set all SMTP info correctly so the application will not be able to send the report.

If you want to debug behavior just change the key `DEBUG` to `true`.

For convenience there is a the [.env.example](.env.example) already in this repo.

All environment variables have self explanatory names but a note about `EMAIL_RECIPIENTS` and `EMAIL_CARBON_COPY_RECIPIENTS` is that both accept more than one email address, just add all of them separated by comma like in a CSV file.

The `DEVOPS_USER` and `DEVOPS_PASSWORD` are used to log in at team's current sprint backlog page and take a screenshot. There is a API to get the burndown image but it only works for teams that use Remaining Work as their burndown measure.

## 3. Run 🏃‍♂️

After setting the `.env` file just run the command `yarn` to install all dependency packages and after it finished run `yarn start` or for short `yarn && yarn start`.

## 4. Notes ❗
1. At this version you will need to schedule this application. If you plan to send a daily report automatically because there's no automatic task scheduler control which maintains this app running and executing only in a specific time.
2. If you don't want to schedule this application as a task, keep in mind that you will need to run every time that send a daily report is necessary.
Binary file added assets/images/daily-report-footer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/daily-report-header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions assets/templates/body.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<div style="overflow-x:auto;">
<h1><%= it.sprint.name %> (de <%= `${it.sprint.attributes.startDate.getDate() + 1}/${it.sprint.attributes.startDate.getMonth() + 1}` %> até <%= `${it.sprint.attributes.finishDate.getDate() + 1}/${it.sprint.attributes.finishDate.getMonth() + 1}` %>)</h1>
<table id="backlog">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Tipo</th>
<th scope="col">Descrição</th>
<th scope="col">Pontos</th>
<th scope="col">Estado</th>
</tr>
</thead>
<tbody>
<% it.backlog.forEach(function(backlogItem) { %>
<%
var stateClass = '';
var stateText = '';
switch(backlogItem.state) {
case 'New':
stateClass = 'sprint-backlog';
stateText = 'Sprint Backlog';
break;
case 'Dev':
stateClass = 'development';
stateText = 'Em Desenvolvimento';
break;
case 'Homologação':
stateClass = 'homologation';
stateText = 'Em Homologação';
break;
case 'Closed':
stateClass = 'closed';
stateText = 'Finalizado';
break;
}
%>
<tr>
<td class="text-center"><%= backlogItem.id %></td>
<td class="text-center"><%= backlogItem.type %></td>
<td><a href="<%= backlogItem.url %>" target="_blank"><%= backlogItem.title %></a></td>
<td class="text-center"><%= backlogItem.storyPoints || 'N/A' %></td>
<td class="<%= stateClass %> text-center"><%= stateText %></td>
</tr>
<% }) %>
</tbody>
</table>
</div>

<div>
<h1>Saúde da sprint</h1>
<img src="data:image/png;base64,<%= it.burndown %>" alt="Burndown <%= it.sprint.name %>" />
</div>
66 changes: 66 additions & 0 deletions assets/templates/daily-report.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!doctype html>
<html lang="pt">

<head>
<title>Report Diário</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<style>
html, body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.sprint-backlog {
background-color: #512D6D;
color: white;
}

.development {
background-color: #2055A6;
color: white;
}

.homologation {
background-color: #33B4C4;
color: white;
}

.blocked {
background-color: #F06400;
color: #000
}

.closed {
background-color: #A8C700;
color: #000
}

.text-center {
text-align: center;
}

#backlog {
border-collapse: collapse;
}

#backlog td, #backlog th {
border: 1px solid #ddd;
padding: 8px;
}

#backlog th {
padding-top: 12px;
padding-bottom: 12px;
text-align: center;
background-color: #1b82fc;
color: white;
}
</style>
</head>

<body>
<%~ await includeFile('./header') %>
<%~ await includeFile('./body', it) %>
<%~ await includeFile('./footer') %>
</body>

</html>
1 change: 1 addition & 0 deletions assets/templates/footer.eta

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions assets/templates/header.eta

Large diffs are not rendered by default.

Loading

0 comments on commit f88fe0e

Please sign in to comment.