Last active
February 19, 2018 10:11
-
-
Save SebastienTainon/d3f2c145a40c4c55ad3405bea580cb37 to your computer and use it in GitHub Desktop.
Daily Scrum Helper with integration with Jira, Github and Google Calendar API
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
// In Google Drive, create a new document of type Google Script. If it does not exist, use "Connect more apps" to enable Google Scripts | |
// Copy-paste this script into the content of the Google Script | |
// This script sends you at each execution an email with Github commits of last day, Jira modified tickets of last day, Google Calendar events of last day, and Google Calendar events of current day | |
// For Jira, just put your username and password. Use https://id.atlassian.com to get them, change password if necessary | |
// For Calendar access, in Google Script, go to Resources > Advanced Google Services and enable "Calendar API" | |
// For Github, it's complicated... you have to follow this tutorial: https://www.benlcollins.com/apps-script/oauth-github | |
// Last step, make the script a daily cron: go to Edit > Current project's triggers and run "sendDailyReport" every day between 5am and 6am | |
// You can run manually "sendDailyReport" to test if it's working ;) | |
// Settings | |
var jiraUsername = ''; // Your Jira e-mail | |
var jiraPassword = ''; // Your Jira password | |
var githubAuthorName = ''; // Your Github username | |
var githubAppClientId = ''; // Github client id (cf above, tutorial) | |
var githubAppClientSecret = ''; // Github client secret (cf above, tutorial) | |
// Functions | |
function sendDailyReport() { | |
var date = new Date(); | |
// If it's WE | |
if (date.getDay() === 6 || date.getDay() === 0) { | |
// Do nothing | |
return null; | |
} | |
// If it's monday | |
if (date.getDay() === 1) { | |
var yesterdayTextPreprosition = "de vendredi"; | |
var yesterdayText = "vendredi"; | |
var yesterdayDate = new Date(date.getTime() - 24 * 3 * 60 * 60 * 1000); | |
} else { | |
var yesterdayTextPreprosition = "d'hier"; | |
var yesterdayText = "hier"; | |
var yesterdayDate = new Date(date.getTime() - 24 * 60 * 60 * 1000); | |
} | |
yesterdayDate.setHours(2, 0, 0); | |
var todayDate = new Date(); | |
todayDate.setHours(2, 0, 0); | |
var tomorrowDate = new Date(date.getTime() + 24 * 60 * 60 * 1000); | |
tomorrowDate.setHours(2, 0, 0); | |
var content = ''; | |
content += '<h2>Commits Github ' + yesterdayTextPreprosition + ' :</h2>'; | |
var githubCommits = getGithubCommits(getFormattedDate(yesterdayDate), getFormattedDate(todayDate)); | |
if (githubCommits.length == 0) { | |
content += '<p>Aucun</p>'; | |
} else { | |
content += '<ul>'; | |
for (var i = 0; i < githubCommits.length; i++) { | |
content += '<li>' + githubCommits[i] + '</li>'; | |
} | |
content += '</ul>'; | |
} | |
content += '<h2>Tickets JIRA modifiés ' + yesterdayText + ' :</h2>'; | |
var jiraEvents = getJiraEvents(yesterdayDate.toISOString().split('T')[0]); | |
if (jiraEvents.length == 0) { | |
content += '<p>Aucun</p>'; | |
} else { | |
content += '<ul>'; | |
for (var i = 0; i < jiraEvents.length; i++) { | |
content += '<li>' + jiraEvents[i] + '</li>'; | |
} | |
content += '</ul>'; | |
} | |
// Google Calendar: yesterday events | |
content += '<h2>Evènements ' + yesterdayTextPreprosition + ' :</h2>'; | |
var yesterdayEvents = getCalendarEvents(yesterdayDate.toISOString(), todayDate.toISOString()); | |
if (yesterdayEvents.length == 0) { | |
content += '<p>Aucun</p>'; | |
} else { | |
content += '<ul>'; | |
for (var i = 0; i < yesterdayEvents.length; i++) { | |
content += '<li>' + yesterdayEvents[i] + '</li>'; | |
} | |
content += '</ul>'; | |
} | |
// Google Calendar: today events | |
content += '<h2>Evènements d\'aujourd\'hui :</h2>'; | |
var todayEvents = getCalendarEvents(todayDate.toISOString(), tomorrowDate.toISOString()); | |
if (todayEvents.length == 0) { | |
content += '<p>Aucun</p>'; | |
} else { | |
content += '<ul>'; | |
for (var i = 0; i < todayEvents.length; i++) { | |
content += '<li>' + todayEvents[i] + '</li>'; | |
} | |
content += '</ul>'; | |
} | |
if (githubCommits.length > 0 || jiraEvents.length > 0 || yesterdayEvents.length > 0 || todayEvents.length) { | |
// Send mail | |
var dateString = ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth()+1)).slice(-2); | |
var email = Session.getActiveUser().getEmail(); | |
var subject = 'Daily scrum ' + dateString; | |
var body = '<body><h1>Pour le daily du ' + dateString + ' :</h1>' + content; | |
GmailApp.sendEmail(email, subject, body, {htmlBody: body}); | |
} | |
} | |
function parseDate(string) { | |
var parts = string.split('T'); | |
parts[0] = parts[0].replace(/-/g, '/'); | |
parts[1] = parts[1].split('+')[0]; | |
return new Date(parts.join(' ')); | |
} | |
function getCalendarEvents(timeMin, timeMax) { | |
var calendarId = 'primary'; | |
var events = Calendar.Events.list(calendarId, { | |
timeMin: timeMin, | |
timeMax: timeMax, | |
singleEvents: true, | |
orderBy: 'startTime', | |
maxResults: 10 | |
}); | |
Logger.log(events); | |
var finalEvents = []; | |
if (events.items && events.items.length > 0) { | |
for (var i = 0; i < events.items.length; i++) { | |
var event = events.items[i]; | |
if (!event.start.date) { | |
var startString = Utilities.formatDate(parseDate(event.start.dateTime), 'Europe/Paris', 'HH:mm'); | |
var endString = Utilities.formatDate(parseDate(event.end.dateTime), 'Europe/Paris', 'HH:mm'); | |
Logger.log('%s (%s)', event.summary, startString); | |
finalEvents.push(Utilities.formatString('%s (%s - %s)', event.summary, startString, endString)); | |
} | |
} | |
} else { | |
Logger.log('No events found.'); | |
} | |
return finalEvents; | |
} | |
function getJiraEvents(timeMin) { | |
var baseURL = "https://yoopies.atlassian.net/rest/api/2/search"; | |
var encCred = Utilities.base64Encode(jiraUsername+":"+jiraPassword); | |
var fetchArgs = { | |
contentType: "application/json", | |
headers: {"Authorization":"Basic "+encCred}, | |
muteHttpExceptions : true | |
}; | |
var issues = []; | |
Logger.log(timeMin); | |
var jql = "?jql=assignee = currentUser() AND updatedDate %3E= " + timeMin + " ORDER BY updated ASC"; | |
var httpResponse = UrlFetchApp.fetch(baseURL + jql, fetchArgs); | |
if (httpResponse) { | |
var rspns = httpResponse.getResponseCode(); | |
Logger.log(rspns); | |
switch(rspns){ | |
case 200: | |
var data = JSON.parse(httpResponse.getContentText()); | |
Logger.log(data); | |
for(var id in data["issues"]) { | |
// Check the data is valid and the Jira fields exist | |
if(data["issues"][id] && data["issues"][id].fields) { | |
var summary = data["issues"][id].fields.summary; | |
var status = data['issues'][id].fields.status.name; | |
var key = data['issues'][id].key; | |
issues.push(Utilities.formatString('%s - %s (%s)', key, summary, status)); | |
} | |
} | |
break; | |
case 404: | |
Logger.log("Jira 404, no item found"); | |
break; | |
default: | |
Logger.log("Error: " + httpResponse.getContentText()); | |
break; | |
} | |
} | |
else { | |
Logger.log("Jira Error, unable to make requests to Jira!"); | |
} | |
return issues; | |
} | |
function getGithubCommits(timeMin, timeMax) { | |
var service = getGithubService_(); | |
var commits = []; | |
if (service.hasAccess()) { | |
Logger.log("App has access."); | |
var api = "https://api.github.com/search/commits?q=author-date:" + timeMin + ".." + timeMax + "+author:" + githubAuthorName + "&sort=author-date&order=desc"; | |
Logger.log(api); | |
var headers = { | |
"Authorization": "Bearer " + getGithubService_().getAccessToken(), | |
"Accept": "application/vnd.github.cloak-preview" | |
}; | |
Logger.log(headers); | |
var options = { | |
"headers": headers, | |
"method" : "GET", | |
"muteHttpExceptions": true | |
}; | |
var response = UrlFetchApp.fetch(api, options); | |
var json = JSON.parse(response.getContentText()); | |
Logger.log(json); | |
for (var id in json.items) { | |
var message = json.items[id].commit.message; | |
var repository = json.items[id].repository.full_name; | |
commits.push(Utilities.formatString('%s : %s', repository, message)); | |
} | |
} | |
else { | |
Logger.log("App has no access yet."); | |
// open this url to gain authorization from github | |
var authorizationUrl = service.getAuthorizationUrl(); | |
Logger.log("Open the following URL and re-run the script: %s", | |
authorizationUrl); | |
} | |
return commits; | |
} | |
function getGithubService_() { | |
return OAuth2.createService('GitHub') | |
.setAuthorizationBaseUrl('https://github.com/login/oauth/authorize') | |
.setTokenUrl('https://github.com/login/oauth/access_token') | |
.setClientId(githubAppClientId) | |
.setClientSecret(githubAppClientSecret) | |
.setCallbackFunction('authCallback') | |
.setPropertyStore(PropertiesService.getUserProperties()) | |
.setScope('user,repo'); | |
} | |
// handle the callback | |
function authCallback(request) { | |
var githubService = getGithubService_(); | |
var isAuthorized = githubService.handleCallback(request); | |
if (isAuthorized) { | |
return HtmlService.createHtmlOutput('Success! You can close this tab.'); | |
} else { | |
return HtmlService.createHtmlOutput('Denied. You can close this tab'); | |
} | |
} | |
// Logs the redict URI to register | |
function logRedirectUri() { | |
var service = getGithubService_(); | |
Logger.log(service.getRedirectUri()); | |
} | |
// Format date into YYYY-MM-DDTHH:MM:SS+00:00 | |
function getFormattedDate(date) { | |
return date.getFullYear()+'-'+('0' + (date.getMonth()+1)).slice(-2)+'-' +('0' + date.getDate()).slice(-2)+'T'+('0' + date.getHours()).slice(-2)+':'+('0' + date.getMinutes()).slice(-2)+':'+('0' + date.getSeconds()).slice(-2)+"%2B00:00" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment