API Docs for: 0.0.4
Show:

File: lib\gitlab\connection.js

var request = require("request-promise");

/**
 * 
 * @class GITLabConnection
 * @constructor
 * @param {String} name
 * @param {String} fqdn
 * @param {Authentication} authentication
 * @param {Object} configuration
 */
module.exports = function(name, fqdn, authentication, configuration) {
	configuration = configuration || {};
	configuration.requests = configuration.requests || {"retries": 3};
	
	configuration.version = parseInt(configuration.version);
	configuration.version = isNaN(configuration.version) ? 3 : configuration.version;
	var root = fqdn + "api/v" + configuration.version + "/";
	var resolve, connection = this;
	var deploymentKeys = [];
	
	/**
	 * Handles pushing a request to the Gitlab host.
	 * @method retrieveURL
	 * @private
	 * @param {String} url
	 * @param {Object} [options]
	 * @param {Number} [page]
	 * @return {Promise}
	 */
	var retrieveURL = function(url, options, page) {
		options = options || {};
		options.requests = options.requests || {};
		options = Object.assign({}, configuration, options);
		return new Promise(function(done, fail) {
			options = options || {};
			options.attempts = options.attempts || 0;
			options.retries = options.retries || options.requests.retries;
			
			
			if(url.length > 4 && url[0] === "h" && url[1] === "t" && url[2] === "t" && url[3] === "p") {
				
			} else {
				url = root + url;
			}
			
			var requesting = {
				"method": options.method || "GET",
				"url": url,
				"headers": {
					"accept": "application/json"
				},
				"resolveWithFullResponse": true
			};
			
			if(options.method === "POST") {
				requesting.headers["content-type"] = "application/json";
			}
			if(options.body) {
				if(typeof options.body === "string") {
					requesting.body = options.body;
				} else {
					requesting.body = JSON.stringify(options.body);
				}
			}
			
			if(page) {
				requesting.url += requesting.url.indexOf("?") === -1 ? "?page=" + page : "&page=" + page;
			}
			
			authentication.authorize(requesting);
			
//			console.log("Gitlab Request:\n", JSON.stringify(requesting, null, 4));
			
			request(requesting)
			.then(function(response) {
				// Leaving room to expand here
				response.body = JSON.parse(response.body);
				done(response);
			})
			.catch(function(failure) {
				options.attempts++;
				if(options.attempts < options.retries) {
					setTimeout(function() {
						retrieveURL(url, options, page)
						.then(done)
						.catch(fail);
					}, 5000);
				} else {
					fail(failure);
				}
			});
		});
	};

	/**
	 * 
	 * @method addDeployKey
	 * @param {Number} id
	 * @return {Array | > | Number} Current deployment key array.
	 */
	this.addDeployKey = function(id) {
		if(deploymentKeys.indexOf(id) === -1) {
			deploymentKeys.push(id);
		}
		return Object.assign([], deploymentKeys);
	};
	
	/**
	 * 
	 * @method removeDeployKey
	 * @param {Number} id
	 * @return {Array | > | Number} Current deployment key array.
	 */
	this.removeDeployKey = function(id) {
		var index = deploymentKeys.indexOf(id);
		if(index !== -1) {
			deploymentKeys.splice(index, 1);
		}
		return Object.assign([], deploymentKeys);
	};
	
	/**
	 * Manages resolution of all pages for a request an returning all results as one array.
	 * @method retrieveURL
	 * @param {String} url
	 * @return {Promise}
	 */
	this.resolveURL = resolve = function(url, options) {
		options = options || {};
		options.requests = options.requests || {};
		options = Object.assign({}, configuration, options);
		return new Promise(function(done, fail) {
			retrieveURL(url, options)
			.then(function(response) {
//				console.log("Resolving " + url);
//				console.log(response.headers.link + "\n\t>\t" + parseInt(response.headers["x-per-page"]) + " > " + parseInt(response.headers["x-total"]));
//				console.log("Resolving " + url + ":\n", response.headers);
				if(!response.headers["x-per-page"]) {
//					console.log(response.body);
				}
				
				if(response.headers.link && parseInt(response.headers["x-per-page"]) < parseInt(response.headers["x-total"])) {
					var promises = [];
					var page = 1;
					var pages = parseInt(response.headers["x-total-pages"]);
					var results = response.body;
					while(page++ < pages) {
						promises.push(retrieveURL(url, options, page));
					}
					
					Promise.all(promises)
					.then(function(responses) {
						responses.forEach(function(response) {
							results = results.concat(response.body);
						});
						done(results);
					})
					.catch(fail);
				} else {
					done(response.body);
				}
			})
			.catch(function(fault) {
				console.log("Failed Resolving " + url + " [" + fault.statusCode + "]:\n", fault.body);
				fail(fault);
			});
		});
	};
	
	/**
	 * 
	 * @method getProject
	 * @param {Object} identifier
	 * @return {Promise} 
	 */
	this.getProject = function(identifier) {
		return new Promise(function(done, fail) {
			var url, id = parseInt(identifier);
			if(identifier === undefined) {
				url = "projects";
			} else if(id == identifier) {
				url = "projects/" + project;
			} else if(typeof identifier === "string") {
				url = "projects"; // TODO
			} else {
				throw new Error("Unable to use passed identifier to find a project");
			}
			
			resolve(url)
			.then(function(project) {
				if(project instanceof Array) {
					for(var x=0; x<project.length; x++) {
						if(project[x].name === identifier) {
							done(project[x]);
							break;
						}
					}
					fail(new Error("Unable to find project: " + identifier));
				} else {
					done(project);
				}
			})
			.catch(fail);
		});
	};
	
	/**
	 * 
	 * @method getProjectDeployKeys
	 * @param {Project} project
	 * @return {Promise} 
	 */
	this.getProjectDeployKeys = function(project) {
		return new Promise(function(done, fail) {
			resolve("projects/" + project.id + "/deploy_keys")
			.then(function(response) {
				project.deploymentKeys = response || [];
				done(project);
			})
			.catch(fail);
		});
	};
	
	/**
	 * 
	 * @method 
	 * @param {String | Number} identifier Name or ID for the key to enable
	 * @param {Boolean} failable When true, requesting a key that isn't available in the Project will fail
	 * 		the Promise. Otherwise the requested key is simply ignored.
	 * @return {Function | > | Promise | > | Project}
	 */
	this.enableProjectDeployKey = function(identifier, failable) {
		return function(project) {
			return new Promise(function(done, fail) {
				var requesting;
				
				if(typeof identifier === "string") {
					project.deploymentKeys.forEach(function(key) {
						if(key.name === identifier) {
							identifier = key.id;
						}
					});
				}
				
//				if(enable === 0 || enable) {
					enable = "projects/" + project.id + "/deploy_keys/" + identifier + "/enable";
					requesting = {};
					requesting.method = "POST";
					resolve(enable, requesting)
					.then(function() {
						done(project);
					})
					.catch(function(fault) {
						if(failable || fault.responseCode !== 404) {
							fail(fault);
						} else {
							done(project);
						}
					});
//				} else {
//					if(failable) {
//						fail(new Error("Key not found"));
//					} else {
//						done(project);
//					}
//				}
			});
		};
	};
	
	/**
	 * 
	 * @method 
	 * @param {Number} identifier ID for the key to delete
	 * @param {Boolean} failable When true, requesting a key that isn't available in the Project will fail
	 * 		the Promise. Otherwise the requested key is simply ignored.
	 * @return {Function | > | Promise | > | Project}
	 */
	this.deleteProjectDeployKey = function(identifier, failable) {
		return function(project) {
			return new Promise(function(done, fail) {
				var requesting = {};
				requesting.method = "DELETE";
				resolve("projects/" + project.id + "/deploy_keys/" + identifier, requesting)
				.then(function() {
					done(project);
				})
				.catch(function(fault) {
					if(failable || fault.responseCode !== 404) {
						fail(fault);
					} else {
						done(project);
					}
				});
			});
		};
	};
	
	/**
	 * 
	 * @method enableSystemProjectDeployKeys
	 * @param {Project} project
	 * @return {Promise | > | Project}
	 */
	this.enableSystemProjectDeployKeys = function(project) {
		return new Promise(function(done, fail) {
			var enabling = [];
			deploymentKeys.forEach(function(key) {
				enabling.push(connection.enableProjectDeployKey(key)(project));
			});
			Promise.all(enabling)
			.then(function() {
				done(project);
			})
			.catch(fail);
		});
	};
	
	/**
	 * 
	 * @method addProjectWebhook
	 * @param {Project} project
	 * @param {String} url Webhook URL
	 * @param {Object} [conditions]
	 * @return {Promise | > | Project}
	 */
	this.addProjectWebhook = function(project, url, conditions) {
		return new Promise(function(done, fail) {
			connection.getProjectWebhooks(project)
			.then(cleanHook(url))
			.then(addWebhook(url, conditions))
			.then(done)
			.catch(fail);
		});
	};
	
	/**
	 * Written to be added to a Promise chain for a project.
	 * 
	 * Deletes any webhook matching the passed URL and finishes when complete.
	 * @method cleanHook
	 * @private
	 * @param {String} url
	 * @return {Promise | > | Project}
	 */
	var cleanHook = function(url) {
		return function(project) {
			return new Promise(function(done, fail) {
				var waiting = [];
				project.webhooks.forEach(function(webhook) {
					if(webhook.url === url) {
						waiting.push(deleteWebhook(project, webhook));
					}
				});
				Promise.all(waiting)
				.then(function() {
					done(project);
				})
				.catch(fail);
			});
		};
	};
	
	/**
	 * 
	 * @method getProjectWebhooks
	 * @param {Project} project
	 * @return {Promise | > | Project}
	 */
	var getProjectWebhooks = this.getProjectWebhooks = function(project) {
		return new Promise(function(done, fail) {
			resolve("projects/" + project.id + "/hooks")
			.then(function(response) {
				console.log("Response:", response);
				project.webhooks = response.body || response;
				done(project);
			})
			.catch(function(fault) {
				fail(fault);
			});
		});
	};
	
	/**
	 * Written to be added to a Promise chain for a project.
	 * @method addWebhook
	 * @private
	 * @param {String} url
	 * @param {Object} [conditions]
	 * @return {Promise | > | Project}
	 */
	var addWebhook = function(url, conditions) {
		return function(project) {
			return new Promise(function(done, fail) {
				var requesting = {};
				requesting.method = "POST";
				requesting.body = {
					"id": project.id,
					"url": url
				};
				Object.assign(requesting.body, conditions);
				console.log("Make Hook:\n", JSON.stringify(requesting, null, 4));
				
				resolve("projects/" + project.id + "/hooks", requesting)
				.then(function(response) {
					console.log("Response:", response.message);
					done(project);
				})
				.catch(function(fault) {
					fail(fault);
				});
			});
		};
	};
	
	/**
	 * 
	 * @method deleteWebhook
	 * @param {Project} project
	 * @param {String} [branch]
	 */
	var deleteWebhook = function(project, webhook) {
		return new Promise(function(done, fail) {
			var requesting = {};
			requesting.method = "DELETE";
			resolve("projects/" + project.id + "/hooks/" + (webhook.id || webhook), requesting)
			.then(function(response) {
				done(project);
			})
			.catch(function(fault) {
				fail(fault);
			});
		});
	};
	
	/**
	 * 
	 * @method getCommits
	 * @param {Project} project
	 * @param {String} [branch]
	 */
	this.getCommits = function(project, branch) {
		return new Promise(function(done, fail) {
			var commits = [];
			var url = "projects/" + project.id + "/repository/commits?per_page=100";
			if(branch) {
				url += "&ref_name=" + branch;
			}

			commitChain(url, commits, done, fail)
		});
	};
	
	/**
	 * Internal method for resolving a request for commits
	 * @method commitChain
	 * @private
	 * @param {String} url
	 * @param {Array} commits
	 * @param {Function} finish
	 * @param {Function} failure
	 */
	var commitChain = function(url, commits, finish, failure) {
		var path = url;
		if(commits.length) {
			path += "&until=" + commits[commits.length-1].created_at;
		}
		resolve(path)
		.then(function(toAdd) {
			commits = commits.concat(toAdd);
			if(toAdd.length === 100) {
				setTimeout(function() {
					commitChain(url, commits, finish, failure);
				}, 0);
			} else {
				finish(commits);
			}
		})
		.catch(failure);
	};
};