Skip to content

Instantly share code, notes, and snippets.

@AlphaGit
Last active December 17, 2016 21:31
Show Gist options
  • Save AlphaGit/11253803388829d7d051 to your computer and use it in GitHub Desktop.
Save AlphaGit/11253803388829d7d051 to your computer and use it in GitHub Desktop.
Google Script: automatically logging calendar times to JIRA
function logHoursForToday() {
setDatesToYesterday();
var options = readOptions();
logHours(options);
}
function setDatesToYesterday() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Setup");
// based on https://developers.google.com/adwords/scripts/docs/features/dates#creating_a_date_object_from_a_formatted_date_string
var today = new Date();
var timeZone = CalendarApp.getTimeZone();
var endDate = Utilities.formatDate(today, timeZone, 'MMMM dd, yyyy 00:00:00 Z')
var yesterday = new Date(today - (24 * 60 * 60 * 1000));
var startDate = Utilities.formatDate(yesterday, timeZone, 'MMMM dd, yyyy 00:00:00 Z')
sheet.getRange("E1").setValue(startDate);
sheet.getRange("E2").setValue(endDate);
}
function arrayFilter(array, evaluator) {
var newArray = [];
for (var index = 0; index < array.length; index++) {
var value = array[index];
if (evaluator(value)) {
newArray.push(value);
}
}
return newArray;
}
function logHours(options) {
if (!options) {
options = readOptions();
}
if (!validateOptions(options)) return;
for (var counter = 0; counter < options.calendarNames.length; counter++) {
var calendarName = options.calendarNames[counter];
var jiraTicketID = options.jiraTicketIDs[counter];
var calendar = CalendarApp.getCalendarsByName(calendarName)[0];
if (!calendar) continue;
var calendarEvents = calendar.getEvents(options.dateFrom, options.dateTo);
for (var calendarIndex = 0; calendarIndex < calendarEvents.length; calendarIndex++) {
var calendarEvent = calendarEvents[calendarIndex];
var title = calendarEvent.getTitle();
var eventStartTime = calendarEvent.getStartTime();
var eventEndTime = calendarEvent.getEndTime();
var duration = ((eventEndTime - eventStartTime) / (1000 * 60)).toString() + "m";
createWorklogInJIRA(options.jiraLocation, options.jiraUserName, options.jiraPassword, jiraTicketID, title, eventStartTime, duration);
}
}
}
function createWorklogInJIRA(baseUrl, userName, password, ticketId, worklogDescription, worklogStartTime, worklogDuration) {
// JIRA REST APIs: https://docs.atlassian.com/jira/REST/latest/
// from: https://developer.atlassian.com/jiradev/api-reference/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-basic-authentication
var authorizationHeaderValue = "Basic " + Utilities.base64Encode(userName + ":" + password);
var fullTicketUrl = baseUrl + "/rest/tempo-rest/1.0/worklogs/" + ticketId;
var timeZone = CalendarApp.getTimeZone();
var ansiWorklogDate = Utilities.formatDate(worklogStartTime, timeZone, 'yyyy-MM-dd');
var tempoWorklogDate = Utilities.formatDate(worklogStartTime, timeZone, 'MMM/dd/yy');
var payload = {
planning: false,
user: userName,
issue: ticketId,
ansidate: ansiWorklogDate,
ansienddate: ansiWorklogDate,
date: tempoWorklogDate,
enddate: tempoWorklogDate,
time: worklogDuration,
remainingEstimate: 0,
comment: worklogDescription
};
var response = UrlFetchApp.fetch(fullTicketUrl, {
method: "post",
headers: {
Authorization: authorizationHeaderValue
},
muteHttpExceptions: true,
payload: payload
});
var responseCode = response.getResponseCode();
var responseContent = response.getContentText();
if (responseCode >= 300 || responseCode < 200) {
Browser.msgBox("Error executing script", "Something went wrong when calling: " + fullTicketUrl + ": " + responseContent, Browser.Buttons.OK);
throw "Error while sending data to JIRA";
}
var xmlResponse = XmlService.parse(responseContent);
if (xmlResponse.getRootElement().getAttribute("valid").getValue() !== "true") {
Browser.msgBox("Error executing script", "Invalid Tempo-API submission: " + responseContent, Browser.Buttons.OK);
}
}
function validateOptions(options) {
var errors = [];
if (!options.dateFrom) errors.push("Date from is required");
if (!options.dateTo) errors.push("Date to is required");
if (options.dateTo < options.dateFrom) errors.push("Date to must be equal or after date from");
if (!options.jiraLocation) errors.push("JIRA Location is required");
if (!options.calendarNames || !options.calendarNames.length) errors.push("At least one calendar name is required");
if (!options.jiraTicketIDs || !options.jiraTicketIDs.length) errors.push("At leats one JIRA ticket is required");
if (options.jiraTicketIDs.length !== options.calendarNames.length) errors.push("There must be a JIRA ticket ID for each calendar");
if (!options.jiraUserName) errors.push("JIRA UserName is required");
if (errors.length) {
Browser.msgBox("Validation errors:\n\n" + errors.join("\n- "));
}
return !errors.length;
}
function readOptions() {
var optionsSheet = SpreadsheetApp.getActive().getSheetByName("Setup");
var allCalendarNames = optionsSheet.getRange("A2:A100").getValues().map(function (calendarRow) {
return calendarRow[0];
});
var calendarNames = arrayFilter(allCalendarNames, function(c) { return !!c; });
var allJiraTicketIDs = optionsSheet.getRange("B2:B100").getValues().map(function (jiraTicketsRow) {
return jiraTicketsRow[0];
});
var jiraTicketIDs = arrayFilter(allJiraTicketIDs, function(j) { return !!j; });
return {
dateFrom: optionsSheet.getRange("E1").getValue(),
dateTo: optionsSheet.getRange("E2").getValue(),
jiraLocation: optionsSheet.getRange("E3").getValue(),
jiraUserName: optionsSheet.getRange("E4").getValue(),
jiraPassword: optionsSheet.getRange("E5").getValue(),
calendarNames: calendarNames,
jiraTicketIDs: jiraTicketIDs
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment