<commit_before>Assembla = {
	milestonesUrl: 'https://api.assembla.com/v1/spaces/shopstyle/milestones.json',
	ticketsUrl: 'https://api.assembla.com/v1/spaces/shopstyle/tickets/milestone/',
	usersUrl: 'https://api.assembla.com/v1/spaces/shopstyle/users.json',
	assemblaUrl: 'https://www.assembla.com/spaces/shopstyle/tickets/',
	ticketUrl: 'https://api.assembla.com/v1/spaces/shopstyle/tickets/',
	testscriptsAndcommentRegex: /TESTING([\s\S]*)END/,
	commentRegex: /COMMENTS([\s\S]*?)(?=TESTSCRIPT)/,
	testscriptsRegex: /TESTSCRIPT([\s\S]*)/,
	// singleTestscriptRegex: /\*\*(\d+)\n*([\s\S]*)/i,
	// correctFormatRegex: /\*\*TESTING\n*\*\*COMMENTS\n*([\s\S]*)\*\*END/i,
	streamUrl: 'https://api.assembla.com/v1/activity.json',
	_headers: {
		'X-Api-Key': Meteor.settings.API_KEY,
	    'X-Api-Secret': Meteor.settings.API_SECRET
	}
};

Assembla.makeGetRequest = function(url, params) {
	return Meteor.http.get(url, {
		headers: Assembla._headers,
		params: params
	});
}

Assembla.makePutRequest = function(url, data) {
	return Meteor.http.put(url, {
		headers: Assembla._headers,
		data: data
	});
}

Assembla.updateMilestoneCollection = function() {
	if (!Meteor.settings.API_KEY || !Meteor.settings.API_SECRET) {
		throw new Meteor.Error(500, 'Please provide secret/key in Meteor.settings');
	}
	
	var milestoneResponse = Assembla.makeGetRequest(Assembla.milestonesUrl, {per_page: 50});
	if (milestoneResponse.statusCode == 200) {
		_.each(milestoneResponse.data, function(milestone) {
			Milestones.update({id: milestone.id}, {
				$set: {
					id: milestone.id,
					title: milestone.title
				}}, {upsert: true});	
		})
	}
	else {
		throw new Meteor.Error(500, 'Assembla call failed');
	}
	Milestones.remove({ title: { $in: 
		["Bug Backlog", "Enhancement Backlog", "Bug Hit List", "Pending Prioritization",
		 "Reports ", "Ongoing Tasks", "Monday Meeting Discussion", "Android Fixes for Mobile Web", "Testing"] 
	}});
}

// Assembla.addTestscriptTicketDescription = function(testscript, ticket) {
// 	var newDescription;
// 	var currentDescription = ticket.description;
// 	var innerDescription = currentDescription.match(Assembla.testscriptsAndcommentRegex);
// 	
// 	if (innerDescription) {
// 		innerDescription = innerDescription[1];
// 		var noTestDescription = currentDescription.replace(Assembla.testscriptsAndcommentRegex, '');
// 		innerDescription += '**' + testscript.testscriptNum + '\n' + testscript.steps;
// 		newDescription = noTestDescription + '**TESTING\n' + innerDescription + '\n**ENDSCRIPT\n**END';
// 	}
// 	else {
// 		var testing = '\n\n**TESTING\n**COMMENTS\n**TESTSCRIPTS\n**';
// 		testing += testscript.testscriptNum + '\n' + testscript.steps;
// 		testing += '\n**ENDSCRIPT\n**END';
// 		newDescription = currentDescription + testing;
// 	}
// 	
// 	Tickets.update({assemblaId: ticket.assemblaId}, {$set: {description: newDescription}});
// 	return newDescription;
// }

// Assembla.editTestscriptTicketDescription = function(id, remove) {
// 	var testscript = Testscripts.findOne(id);
// 	var ticket = Tickets.findOne({assemblaId: testscript.ticketAssemblaId});
// 	var oldTestDesc = ticket.description.match(Assembla.testscriptsAndcommentRegex);
// 
// 	if (remove && oldTestDesc) {
// 		Assembla._updateAssemblaTicketDescription(testscript, ticket, oldTestDesc, '');
// 	}
// 	else if (oldTestDesc) {
// 		Assembla._updateAssemblaTicketDescription(testscript, ticket, oldTestDesc);
// 	}
// }

// Assembla.updateTicketCommentDescription = function(oldComments, newComments, assemblaId) {
// 	var newDescription;
// 	var ticket = Tickets.findOne({assemblaId: assemblaId});
// 	var oldDesc = ticket.description;
// 	var ticketHasTestingNotes = oldDesc.match(Assembla.correctFormatRegex);
// 	
// 	if (oldComments) {
// 		newDescription = oldDesc.replace(oldComments, newComments);
// 		Assembla._setNewDescription(newDescription, ticket.assemblaId);
// 	}
// 	// else if (!ticketHasTestingNotes) {
// // 		newDescription = oldDesc + '\n\n**TESTING\n**COMMENTS\n' + newComments + '**TESTSCRIPTS\n**END';
// // 	}
// }

// Assembla._setNewDescription = function(newDescription, assemblaId) {
// 	Tickets.update({ assemblaId: assemblaId}, {$set: {description: newDescription}});
// 	var url = Assembla.ticketUrl + assemblaId + '.json';
// 	Assembla.makePutRequest(url, {"ticket": {"description": newDescription}});
// }
// 
// Assembla._updateAssemblaTicketDescription = function(testscript, ticket, oldTestDesc, newSteps) {
// 	var testscriptRegex = new RegExp("(\\*\\*" 
// 		+ testscript.testscriptNum + "[\\s\\S]*?\\*\\*ENDSCRIPT\\n*)", "i");
// 	var oldSteps = oldTestDesc[1].match(testscriptRegex);
// 	
// 	if (newSteps === undefined) {
// 		var newSteps = "\*\*" + testscript.testscriptNum 
// 			+ "\n" + testscript.steps + "\n\*\*ENDSCRIPT\n";
// 	}
// 	var newTestDesc = oldTestDesc[1].replace(oldSteps[1], newSteps);
// 	
// 	var newDescription = ticket.description.replace(oldTestDesc[1], newTestDesc);
// 	Assembla._setNewDescription(newDescription, ticket.assemblaId);
// }
// 
// Assembla.createTestscript = function(testscript, ticket) {
// 	var description = Assembla.addTestscriptTicketDescription(testscript, ticket);
// 	Assembla._setNewDescription(description, ticket.assemblaId);
// }

Assembla.extractTicketInfoFromDescription = function(description, ticketNumber) {
	if (description) {
		var innerDescription = description.match(Assembla.testscriptsAndcommentRegex);
		if (innerDescription) {
			Assembla._extractTestscriptsFromInnerDescription(innerDescription[1], ticketNumber);
			return Assembla._extractCommentFromInnerDescription(innerDescription[1]);
		}
	}
	return '';
}

Assembla._extractTestscriptsFromInnerDescription = function(innerDescription, ticketNumber) {
	var testscriptsString = innerDescription.match(Assembla.testscriptsRegex);
	if (!testscriptsString) {
		return;
	}
	var testscripts = testscriptsString[1].split("TESTSCRIPT");

	var testscriptNum = 1;
	var currentTestscripts = [];
	_.each(testscripts, function(testscript) {
		if (testscript.length === 0) {
			return;
		}
		currentTestscripts.push(testscriptNum);
		var testscriptSteps = testscript.replace(/^\s+|\s+$/g, '');
		Testscripts.update({ ticketAssemblaId: ticketNumber, testscriptNum: testscriptNum }, 
			{ $set: 
				{ 
					steps: testscriptSteps,
					ticketAssemblaId: ticketNumber,
					testscriptNum: testscriptNum 
				}
			},
			{ upsert: true }
		);
		testscriptNum += 1;
	});

	Testscripts.remove({ticketAssmblaId: ticketNumber, testscriptNum: {$nin: currentTestscripts}});
	
	//better way for this??
	Testscripts.update({ passers: { $exists: false }}, { $set: { passers: [] }}, { multi: true });
	Testscripts.update({ failers: { $exists: false }}, { $set: { failers: [] }}, { multi: true });	
	Testscripts.update({ status: { $exists: false }}, { $set: { status: '' } }, { multi: true });	
}	
	
Assembla._extractCommentFromInnerDescription = function(innerDescription) {
	var comment = innerDescription.match(Assembla.commentRegex);

	if (comment) {
		if (comment[1]) {
			return	comment[1].replace(/^\s+|\s+$/g, '');
		}
		return ' ';
	}
	return '';
}

Assembla.updateSingleTicket = function(ticket) {
	var assemblaUrl = Assembla.assemblaUrl + ticket.number;
	var extractedComments = Assembla.extractTicketInfoFromDescription(ticket.description, ticket.number);
	var statusName = ticket.status;
	if (statusName === 'Verified on Dev') {
		Tickets.update({assemblaId: ticket.number}, {$set: {status: 'pass'}});
	}
	var description = ticket.description;
	if (!description) {
		description = '';
	}
	
	var noTesting = false;
	if (ticket.custom_fields["No Testing Required"]) {
		if (ticket.custom_fields["No Testing Required"] === "yes") {
			noTesting = true;
		}
	}
	
	Tickets.update({assemblaId: ticket.number}, 
		{
			$set: 
			{
				assignedToId: ticket.assigned_to_id,
				assemblaId: ticket.number,
				milestoneId: ticket.milestone_id,
				updatedAt: ticket.updated_at,
				summary: ticket.summary,
				statusName: statusName,
				component: ticket.custom_fields.Component,
				browser: ticket.custom_fields.Browser,
				os: ticket.custom_fields.OS,
				assemblaUrl: assemblaUrl,
				description: description,
				comments: extractedComments,
				noTesting: noTesting
			}
		}, { upsert: true }
	);
}

Assembla.populateTicketCollection = function() {
	if (!Meteor.settings.API_KEY || !Meteor.settings.API_SECRET) {
		throw new Meteor.Error(500, 'Please provide secret/key in Meteor.settings');
	}
	var currentMilestoneId = Milestones.findOne({ current: true }).id;
	var url = Assembla.ticketsUrl + currentMilestoneId + '.json';
	var ticketResponseAll = Assembla.makeGetRequest(url, {per_page: 100, ticket_status: "all"});
	var ticketResponseClosed = Assembla.makeGetRequest(url, {per_page: 100, ticket_status: "closed"});
	//need a way to deal with over 100 tickets. maybe have a counter, and then just ping again looking for page 2
	if (ticketResponseAll.statusCode == 200 && ticketResponseClosed.statusCode == 200) {
		var ticketResponse = ticketResponseAll.data.concat(ticketResponseClosed.data);
		
		//hack way to deal with a ticket changing milestones and not changing in the app
		Tickets.update({milestoneId: currentMilestoneId}, {$set: {milestoneId: 0}}, {multi: true});
		
		//I really don't like how I am querying the database and setting things in a loop...
		_.each(ticketResponse, function(ticket) {
			Assembla.updateSingleTicket(ticket);
		});
		
		//this is only to make sure tickets have these fields. it might be better to set them when setting
		//properties on the ticket in updateSingleTicket? 
		Tickets.update({ passers: { $exists: false }}, { $set: { passers: [] }}, { multi: true });
		Tickets.update({ failers: { $exists: false }}, { $set: { failers: [] }}, { multi: true });	
		Tickets.update({ status: { $exists: false }}, { $set: { status: '' } }, { multi: true });	
		Tickets.update({ allStepsCompleted: { $exists: false }}, { $set: { allStepsCompleted: [] }}, { multi: true });
	}
	else {
		throw new Meteor.Error(500, 'Assembla call failed');
	}
}

Assembla.populateAssemblaUsers = function() {
	var userResponse = Assembla.makeGetRequest(Assembla.usersUrl, {per_page: 500});
	if (userResponse.statusCode == 200) {
		AssemblaUsers.remove({});
		_.each(userResponse.data, function(user) {
			AssemblaUsers.insert(user);
		});
	}<commit_msg>change for no testing update<commit_after>Assembla = {
	milestonesUrl: 'https://api.assembla.com/v1/spaces/shopstyle/milestones.json',
	ticketsUrl: 'https://api.assembla.com/v1/spaces/shopstyle/tickets/milestone/',
	usersUrl: 'https://api.assembla.com/v1/spaces/shopstyle/users.json',
	assemblaUrl: 'https://www.assembla.com/spaces/shopstyle/tickets/',
	ticketUrl: 'https://api.assembla.com/v1/spaces/shopstyle/tickets/',
	testscriptsAndcommentRegex: /TESTING([\s\S]*)END/,
	commentRegex: /COMMENTS([\s\S]*?)(?=TESTSCRIPT)/,
	testscriptsRegex: /TESTSCRIPT([\s\S]*)/,
	// singleTestscriptRegex: /\*\*(\d+)\n*([\s\S]*)/i,
	// correctFormatRegex: /\*\*TESTING\n*\*\*COMMENTS\n*([\s\S]*)\*\*END/i,
	streamUrl: 'https://api.assembla.com/v1/activity.json',
	_headers: {
		'X-Api-Key': Meteor.settings.API_KEY,
	    'X-Api-Secret': Meteor.settings.API_SECRET
	}
};

Assembla.makeGetRequest = function(url, params) {
	return Meteor.http.get(url, {
		headers: Assembla._headers,
		params: params
	});
}

Assembla.makePutRequest = function(url, data) {
	return Meteor.http.put(url, {
		headers: Assembla._headers,
		data: data
	});
}

Assembla.updateMilestoneCollection = function() {
	if (!Meteor.settings.API_KEY || !Meteor.settings.API_SECRET) {
		throw new Meteor.Error(500, 'Please provide secret/key in Meteor.settings');
	}
	
	var milestoneResponse = Assembla.makeGetRequest(Assembla.milestonesUrl, {per_page: 50});
	if (milestoneResponse.statusCode == 200) {
		_.each(milestoneResponse.data, function(milestone) {
			Milestones.update({id: milestone.id}, {
				$set: {
					id: milestone.id,
					title: milestone.title
				}}, {upsert: true});	
		})
	}
	else {
		throw new Meteor.Error(500, 'Assembla call failed');
	}
	Milestones.remove({ title: { $in: 
		["Bug Backlog", "Enhancement Backlog", "Bug Hit List", "Pending Prioritization",
		 "Reports ", "Ongoing Tasks", "Monday Meeting Discussion", "Android Fixes for Mobile Web", "Testing"] 
	}});
}

// Assembla.addTestscriptTicketDescription = function(testscript, ticket) {
// 	var newDescription;
// 	var currentDescription = ticket.description;
// 	var innerDescription = currentDescription.match(Assembla.testscriptsAndcommentRegex);
// 	
// 	if (innerDescription) {
// 		innerDescription = innerDescription[1];
// 		var noTestDescription = currentDescription.replace(Assembla.testscriptsAndcommentRegex, '');
// 		innerDescription += '**' + testscript.testscriptNum + '\n' + testscript.steps;
// 		newDescription = noTestDescription + '**TESTING\n' + innerDescription + '\n**ENDSCRIPT\n**END';
// 	}
// 	else {
// 		var testing = '\n\n**TESTING\n**COMMENTS\n**TESTSCRIPTS\n**';
// 		testing += testscript.testscriptNum + '\n' + testscript.steps;
// 		testing += '\n**ENDSCRIPT\n**END';
// 		newDescription = currentDescription + testing;
// 	}
// 	
// 	Tickets.update({assemblaId: ticket.assemblaId}, {$set: {description: newDescription}});
// 	return newDescription;
// }

// Assembla.editTestscriptTicketDescription = function(id, remove) {
// 	var testscript = Testscripts.findOne(id);
// 	var ticket = Tickets.findOne({assemblaId: testscript.ticketAssemblaId});
// 	var oldTestDesc = ticket.description.match(Assembla.testscriptsAndcommentRegex);
// 
// 	if (remove && oldTestDesc) {
// 		Assembla._updateAssemblaTicketDescription(testscript, ticket, oldTestDesc, '');
// 	}
// 	else if (oldTestDesc) {
// 		Assembla._updateAssemblaTicketDescription(testscript, ticket, oldTestDesc);
// 	}
// }

// Assembla.updateTicketCommentDescription = function(oldComments, newComments, assemblaId) {
// 	var newDescription;
// 	var ticket = Tickets.findOne({assemblaId: assemblaId});
// 	var oldDesc = ticket.description;
// 	var ticketHasTestingNotes = oldDesc.match(Assembla.correctFormatRegex);
// 	
// 	if (oldComments) {
// 		newDescription = oldDesc.replace(oldComments, newComments);
// 		Assembla._setNewDescription(newDescription, ticket.assemblaId);
// 	}
// 	// else if (!ticketHasTestingNotes) {
// // 		newDescription = oldDesc + '\n\n**TESTING\n**COMMENTS\n' + newComments + '**TESTSCRIPTS\n**END';
// // 	}
// }

// Assembla._setNewDescription = function(newDescription, assemblaId) {
// 	Tickets.update({ assemblaId: assemblaId}, {$set: {description: newDescription}});
// 	var url = Assembla.ticketUrl + assemblaId + '.json';
// 	Assembla.makePutRequest(url, {"ticket": {"description": newDescription}});
// }
// 
// Assembla._updateAssemblaTicketDescription = function(testscript, ticket, oldTestDesc, newSteps) {
// 	var testscriptRegex = new RegExp("(\\*\\*" 
// 		+ testscript.testscriptNum + "[\\s\\S]*?\\*\\*ENDSCRIPT\\n*)", "i");
// 	var oldSteps = oldTestDesc[1].match(testscriptRegex);
// 	
// 	if (newSteps === undefined) {
// 		var newSteps = "\*\*" + testscript.testscriptNum 
// 			+ "\n" + testscript.steps + "\n\*\*ENDSCRIPT\n";
// 	}
// 	var newTestDesc = oldTestDesc[1].replace(oldSteps[1], newSteps);
// 	
// 	var newDescription = ticket.description.replace(oldTestDesc[1], newTestDesc);
// 	Assembla._setNewDescription(newDescription, ticket.assemblaId);
// }
// 
// Assembla.createTestscript = function(testscript, ticket) {
// 	var description = Assembla.addTestscriptTicketDescription(testscript, ticket);
// 	Assembla._setNewDescription(description, ticket.assemblaId);
// }

Assembla.extractTicketInfoFromDescription = function(description, ticketNumber) {
	if (description) {
		var innerDescription = description.match(Assembla.testscriptsAndcommentRegex);
		if (innerDescription) {
			Assembla._extractTestscriptsFromInnerDescription(innerDescription[1], ticketNumber);
			return Assembla._extractCommentFromInnerDescription(innerDescription[1]);
		}
	}
	return '';
}

Assembla._extractTestscriptsFromInnerDescription = function(innerDescription, ticketNumber) {
	var testscriptsString = innerDescription.match(Assembla.testscriptsRegex);
	if (!testscriptsString) {
		return;
	}
	var testscripts = testscriptsString[1].split("TESTSCRIPT");

	var testscriptNum = 1;
	var currentTestscripts = [];
	_.each(testscripts, function(testscript) {
		if (testscript.length === 0) {
			return;
		}
		currentTestscripts.push(testscriptNum);
		var testscriptSteps = testscript.replace(/^\s+|\s+$/g, '');
		Testscripts.update({ ticketAssemblaId: ticketNumber, testscriptNum: testscriptNum }, 
			{ $set: 
				{ 
					steps: testscriptSteps,
					ticketAssemblaId: ticketNumber,
					testscriptNum: testscriptNum 
				}
			},
			{ upsert: true }
		);
		testscriptNum += 1;
	});

	Testscripts.remove({ticketAssmblaId: ticketNumber, testscriptNum: {$nin: currentTestscripts}});
	
	//better way for this??
	Testscripts.update({ passers: { $exists: false }}, { $set: { passers: [] }}, { multi: true });
	Testscripts.update({ failers: { $exists: false }}, { $set: { failers: [] }}, { multi: true });	
	Testscripts.update({ status: { $exists: false }}, { $set: { status: '' } }, { multi: true });	
}	
	
Assembla._extractCommentFromInnerDescription = function(innerDescription) {
	var comment = innerDescription.match(Assembla.commentRegex);

	if (comment) {
		if (comment[1]) {
			return	comment[1].replace(/^\s+|\s+$/g, '');
		}
		return ' ';
	}
	return '';
}

Assembla.updateSingleTicket = function(ticket) {
	var assemblaUrl = Assembla.assemblaUrl + ticket.number;
	var extractedComments = Assembla.extractTicketInfoFromDescription(ticket.description, ticket.number);
	var statusName = ticket.status;
	if (statusName === 'Verified on Dev') {
		Tickets.update({assemblaId: ticket.number}, {$set: {status: 'pass'}});
	}
	var description = ticket.description;
	if (!description) {
		description = '';
	}
	
	var noTesting = false;
	if (ticket.custom_fields["No Testing Required"]) {
		if (ticket.custom_fields["No Testing Required"] === "yes") {
			noTesting = true;
		}
	}
	
	Tickets.update({assemblaId: ticket.number}, 
		{
			$set: 
			{
				assignedToId: ticket.assigned_to_id,
				assemblaId: ticket.number,
				milestoneId: ticket.milestone_id,
				updatedAt: ticket.updated_at,
				summary: ticket.summary,
				statusName: statusName,
				component: ticket.custom_fields.Component,
				browser: ticket.custom_fields.Browser,
				os: ticket.custom_fields.OS,
				assemblaUrl: assemblaUrl,
				description: description,
				comments: extractedComments,
				noTesting: noTesting
			}
		}, { upsert: true }
	);
}

Assembla.populateTicketCollection = function() {
	if (!Meteor.settings.API_KEY || !Meteor.settings.API_SECRET) {
		throw new Meteor.Error(500, 'Please provide secret/key in Meteor.settings');
	}
	var currentMilestoneId = Milestones.findOne({ current: true }).id;
	var url = Assembla.ticketsUrl + currentMilestoneId + '.json';
	var ticketResponseAll = Assembla.makeGetRequest(url, {per_page: 100, ticket_status: "all"});
	var ticketResponseClosed = Assembla.makeGetRequest(url, {per_page: 100, ticket_status: "closed"});
	//need a way to deal with over 100 tickets. maybe have a counter, and then just ping again looking for page 2
	if (ticketResponseAll.statusCode == 200 && ticketResponseClosed.statusCode == 200) {
		var ticketResponse = ticketResponseAll.data.concat(ticketResponseClosed.data);
		
		//hack way to deal with a ticket changing milestones and not changing in the app
		Tickets.update({milestoneId: currentMilestoneId}, {$set: {milestoneId: 0}}, {multi: true});
		
		//I really don't like how I am querying the database and setting things in a loop...
		_.each(ticketResponse, function(ticket) {
			Assembla.updateSingleTicket(ticket);
		});
		
		//this is only to make sure tickets have these fields. it might be better to set them when setting
		//properties on the ticket in updateSingleTicket? 
		Tickets.update({ passers: { $exists: false }}, { $set: { passers: [] }}, { multi: true });
		Tickets.update({ failers: { $exists: false }}, { $set: { failers: [] }}, { multi: true });	
		Tickets.update({ status: { $exists: false }}, { $set: { status: '' } }, { multi: true });	
		Tickets.update({ allStepsCompleted: { $exists: false }}, { $set: { allStepsCompleted: [] }}, { multi: true });
		Tickets.update({ noTesting: true }, { $set: { testers: [] }}, { multi: true });
	}
	else {
		throw new Meteor.Error(500, 'Assembla call failed');
	}
}

Assembla.populateAssemblaUsers = function() {
	var userResponse = Assembla.makeGetRequest(Assembla.usersUrl, {per_page: 500});
	if (userResponse.statusCode == 200) {
		AssemblaUsers.remove({});
		_.each(userResponse.data, function(user) {
			AssemblaUsers.insert(user);
		});
	}
{'fraction_non_alphanumeric': 0.1593853860604017, 'fraction_numerical': 0.005587399450893502, 'mean_word_length': 4.4180584551148225, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 12, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5083115', 'n_tokens_mistral': 7625, 'n_tokens_neox': 6941, 'n_words': 1287}