Skip to content

Instantly share code, notes, and snippets.

@SebastienTainon
Last active February 19, 2018 10:11
Show Gist options
  • Save SebastienTainon/d3f2c145a40c4c55ad3405bea580cb37 to your computer and use it in GitHub Desktop.
Save SebastienTainon/d3f2c145a40c4c55ad3405bea580cb37 to your computer and use it in GitHub Desktop.
Daily Scrum Helper with integration with Jira, Github and Google Calendar API
// 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