-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request agiledev-students-fall2023#62 from lesleyzhao/lesl…
…ie-forked-branch Leslie forked branch
- Loading branch information
Showing
6 changed files
with
176 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"scriptId": "1d-At2A2QTQAobdXicLsAai-_P7OrYovTa4qYOWbtV-3CjJaE8XztRgQ6", | ||
"rootDir": "/Users/foobarstein/Documents/courant/courses/agile-dev-devops/generic-mern-stack-project/automations" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
function emailSprint1ChartsToMe() { | ||
emailChartsToMe('Sprint 1 - Team Plots') | ||
} | ||
|
||
function emailSprint2ChartsToMe() { | ||
emailChartsToMe('Sprint 2 - Team Plots') | ||
} | ||
|
||
function emailSprint3ChartsToMe() { | ||
emailChartsToMe('Sprint 3 - Team Plots') | ||
} | ||
|
||
function emailSprint4ChartsToMe() { | ||
emailChartsToMe('Sprint 4 - Team Plots') | ||
} | ||
|
||
function emailChartsToMe(sheetName) { | ||
const charts = getCharts(sheetName) | ||
const to = Session.getActiveUser().getEmail(); | ||
const replyTo = "[email protected]" | ||
const subject = "Agile Software Development & DevOps - Team Contribution Charts" | ||
const message = generateEmail(charts) | ||
const options = { | ||
replyTo: replyTo | ||
} | ||
|
||
// prepare inline image object | ||
const inlineImages = {} | ||
charts.forEach( (chart, i) => { | ||
inlineImages[`chart_${i}`] = chart | ||
}) | ||
|
||
// GmailApp.sendEmail(to, subject, message, options); | ||
// Send message with inlineImages object, matching embedded tags. | ||
MailApp.sendEmail(to, subject, "", { | ||
htmlBody: message, | ||
inlineImages: inlineImages | ||
}); | ||
|
||
Logger.log(message) | ||
} | ||
|
||
function generateEmail(charts) { | ||
let imageTags = [] | ||
charts.forEach( (chart, i) => { | ||
const tag = `<img src='cid:chart_${i}' />` | ||
imageTags.push(tag) | ||
}) | ||
imageTags = imageTags.join('<br />') // convert to string with line break separator | ||
const message = `<h1>Charts</h1>${imageTags}` | ||
return message | ||
} | ||
|
||
function generateHtml(sheetName, charts) { | ||
// data:image/gif;base64, | ||
let imageTags = [] | ||
charts.forEach( (chart, i) => { | ||
const chartData = Utilities.base64Encode(chart.getBytes()) // get base64 encoded data for this chart | ||
const tag = `<img src='data:image/png;base64,${chartData}' />` | ||
imageTags.push(tag) | ||
}) | ||
imageTags = imageTags.join('<br />') // convert to string with line break separator | ||
const message = `<h1>${sheetName}</h1>${imageTags}` | ||
return message | ||
} | ||
|
||
function getCharts(sheetName) { | ||
// get all charts | ||
// const sheet = SpreadsheetApp.getActiveSheet(); | ||
const ss = SpreadsheetApp.getActiveSpreadsheet() // container spreadsheet | ||
let sheet = ss.getSheetByName(sheetName) // specific worksheet | ||
const range = sheet.getRange("A:Z") | ||
const charts = sheet.getCharts() | ||
|
||
// loop through charts | ||
const images = [] | ||
charts.forEach( (chart, i) => { | ||
Logger.log(`chart id: ${chart.getChartId()}`) | ||
// Logger.log(JSON.stringify(chart.getOptions(), null, 2)) | ||
const image = chart.getAs('image/png') | ||
image.setName(`chart_${i}`) | ||
images.push(image) // add to array | ||
}) | ||
return images | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
const getConfig = () => { | ||
// global settings | ||
return { | ||
defaultChartSheetName: 'Sprint 1 - Team Plots', | ||
logsSheetName: 'GitHub Logs', | ||
logsSheetFields: ['repository', 'event', 'id', 'username', 'email', 'date', 'message', 'num_files', 'num_additions', 'num_deletions'] | ||
} | ||
} | ||
|
||
const getSheet = () => { | ||
const config = getConfig() | ||
const ss = SpreadsheetApp.getActiveSpreadsheet() // container spreadsheet | ||
let sheet = ss.getSheetByName(config.logsSheetName) // specific worksheet | ||
if (sheet == null) { | ||
// create worksheet if none | ||
sheet = ss.insertSheet(config.logsSheetName) | ||
sheet.appendRow(config.logsSheetFields) // heading row | ||
} | ||
return sheet | ||
} | ||
|
||
function doGet(e) { | ||
// get the sheet name with the charts from the query string | ||
const config = getConfig() | ||
// we expect a `sheet` query string in the request | ||
const sheetName = (e.parameter["sheet"]) ? decodeURIComponent(e.parameter["sheet"]) : config.defaultChartSheetName | ||
Logger.log(`Loading charts from sheet: ${sheetName}`) | ||
charts = getCharts(sheetName) | ||
const content = generateHtml(sheetName, charts) | ||
return HtmlService.createHtmlOutput(content) | ||
} | ||
|
||
function doPost(e) { | ||
console.log("Incoming post request") | ||
console.log(JSON.stringify(e, null, 2)) | ||
const sheet = getSheet() | ||
const res = { | ||
type: 'post', | ||
e: e | ||
} | ||
const commit_data = JSON.parse(e.postData.contents); // should be an array of objects | ||
if (Array.isArray(commit_data)) { | ||
for (let i=0; i<commit_data.length; i++) { | ||
// log this commit! | ||
const commit = commit_data[i] | ||
console.log(JSON.stringify(commit, null, 2)) | ||
// append data array to sheet as new row | ||
const row = [commit['repository_url'], commit['event_type'], commit['id'], commit['author_name'], commit['author_email'], commit['date'], commit['message'], commit['files'], commit['additions'], commit['deletions']] | ||
sheet.appendRow(row); | ||
} | ||
return ContentService.createTextOutput(commit_data).setMimeType(ContentService.MimeType.JSON) | ||
} | ||
else { | ||
return ContentService.createTextOutput(typeof(commit_data)).setMimeType(ContentService.MimeType.TEXT) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Automation used to track developer contributions | ||
|
||
The developer activity in this repository is tracked using a combination of custom tools. Any action on this repository triggers a sequence of automated steps: | ||
|
||
1. A GitHub Actions [workflow](../.github/workflows/event-logger.yml) is set up to detect actions on this repository, such as push, pull request, etc. | ||
1. This workflow executes a Python package named [gitcommitlogger](https://pypi.org/project/gitcommitlogger/) that parses the `git` logs and determines what has changed and who made the changes. | ||
1. The Python package then posts this data to a "container-bound" [Google Apps Script](./Code.js) attached to a Google Sheet and set up as a web app to receive such incoming HTTP POST requests. The web app URL where the data is posted is stored in a [GitHub secret](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) named, `COMMIT_LOG_API` within this repository. | ||
1. The Google Apps Script inserts the data posted by the Python package into a new row in the bound spreadsheet. | ||
1. The Google Sheet contains formulae to add up the number of pull requests opened, pull requests closed, commits, files changed, lines of code added. lines of code removed, etc, by each developer, over a given time period, based on these logs. | ||
1. The sums of these metrics are capped for each developer at reasonable, relatively low levels. | ||
1. Based on all developers' activity, an average score for each of these metrics is computed, and each developer's own score is compared to the average of all developers. | ||
1. A contribution score is calculated for each developer: those who perform average or better on all metrics are given a perfect score; those who perform less than average for any metric have their score scaled down in proportion to how much lower than average they performed. | ||
1. Charts of the developers' contributions over a given time period are [made automatically available](./Charts.js) in the web app via HTTP GET requests. | ||
1. These contribution scores are also automatically pulled into a separate gradebook spreadsheet. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"timeZone": "America/New_York", | ||
"dependencies": {}, | ||
"webapp": { | ||
"executeAs": "USER_DEPLOYING", | ||
"access": "ANYONE_ANONYMOUS" | ||
}, | ||
"exceptionLogging": "STACKDRIVER", | ||
"runtimeVersion": "V8" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters