├── .editorconfig ├── .eslintrc ├── .gitignore ├── .prettierrc.js ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── config ├── accountConfig.html ├── config.html └── config.js ├── lib ├── api.js ├── webapp.js ├── webhooks.js └── worker.js ├── package.json ├── test ├── README.md ├── mocha.opts ├── mocks │ ├── gitlab_add_key.js │ ├── gitlab_create_hooks.js │ ├── gitlab_delete_hooks_when_absent.js │ ├── gitlab_delete_hooks_when_present.js │ ├── gitlab_delete_key_when_absent.js │ ├── gitlab_delete_project.js │ ├── gitlab_get.js │ ├── gitlab_webapp_getbranches.js │ ├── gitlab_webapp_getfile.js │ ├── gitlab_webapp_listrepos.js │ ├── gitlab_webapp_setuprepo.js │ ├── gitlab_webapp_teardownrepos.js │ ├── receive_webhooks_req.js │ ├── sample_payload.js │ └── sample_payload_tag_push_with_v7.x.js ├── test_api.js ├── test_webapp.js ├── test_webhooks.js └── test_worker.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # Strider Editor/IDE Settings 2 | # This file is used to promote consistent source code standards 3 | # amongst all Strider-CD contributors. 4 | # More information can be found here: http://editorconfig.org/ 5 | 6 | # General Settings 7 | root = true 8 | 9 | # Settings for all files 10 | [*] 11 | indent_style = space 12 | indent_size = 2 13 | end_of_line = lf 14 | charset = utf-8 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | 18 | # Settings specific to Markdown files 19 | [*.md] 20 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6, 4 | "sourceType": "script" 5 | }, 6 | "env": { 7 | "node": true, 8 | "es6": true 9 | }, 10 | "extends": "eslint:recommended", 11 | "rules": { 12 | "indent": [2, 2], 13 | "brace-style": [2, "1tbs"], 14 | "semi": [2, "always"], 15 | "comma-style": [2, "last"], 16 | "one-var": [2, "never"], 17 | "strict": [2, "global"], 18 | "prefer-template": 2, 19 | "no-console": 0, 20 | "no-use-before-define": [2, "nofunc"], 21 | "no-underscore-dangle": 0, 22 | "no-constant-condition": 0, 23 | "space-before-function-paren": [ 24 | 2, 25 | { "anonymous": "always", "named": "never" } 26 | ], 27 | "func-style": [2, "declaration"] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Deployed apps should consider commenting this line out: 24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 25 | node_modules 26 | 27 | # Webstorm project folder 28 | .idea 29 | .DS_Store 30 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | }; 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '10' 4 | - 'node' 5 | 6 | sudo: false 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [2.0.0](https://github.com/Strider-CD/strider-gitlab/compare/v1.4.0...v2.0.0) (2020-05-02) 6 | 7 | 8 | ### ⚠ BREAKING CHANGES 9 | 10 | * Uses GitLab v4 API 11 | 12 | ### Bug Fixes 13 | 14 | * convert to v4 API ([9bba287](https://github.com/Strider-CD/strider-gitlab/commit/9bba287c66f22fdaeffc55a8f346eee5047f8628)) 15 | 16 | ## [1.4.0](https://github.com/Strider-CD/strider-gitlab/compare/v1.3.1...v1.4.0) (2020-05-02) 17 | 18 | 19 | ### Features 20 | 21 | * add option to limit gitlab results to projects you are a member of ([73b11df](https://github.com/Strider-CD/strider-gitlab/commit/73b11df43ea8a4d8491d02d9829f7bde6ca3a7ee)) 22 | 23 | ### [1.3.1](https://github.com/Strider-CD/strider-gitlab/compare/v1.3.0...v1.3.1) (2020-05-02) 24 | 25 | 26 | ### Bug Fixes 27 | 28 | * actually fix the page issue ([a83536c](https://github.com/Strider-CD/strider-gitlab/commit/a83536c6c60155880658cf20c40254d36cff63fd)) 29 | 30 | ## [1.3.0](https://github.com/Strider-CD/strider-gitlab/compare/v1.2.2...v1.3.0) (2020-05-02) 31 | 32 | 33 | ### Features 34 | 35 | * Tag push support ([#110](https://github.com/Strider-CD/strider-gitlab/issues/110)) ([f7f8d61](https://github.com/Strider-CD/strider-gitlab/commit/f7f8d618fe0cc26305e4adc297dde9d01f0d29fc)) 36 | 37 | 38 | ### Bug Fixes 39 | 40 | * default to 1 page if unknown ([433b279](https://github.com/Strider-CD/strider-gitlab/commit/433b279725e6240d2d161cfce5e077446a855731)) 41 | * **package:** update async to version 2.6.0 ([#111](https://github.com/Strider-CD/strider-gitlab/issues/111)) ([7c3da7a](https://github.com/Strider-CD/strider-gitlab/commit/7c3da7a8bfd1acc2d6ea439bd0d9b769a68faf3c)), closes [#92](https://github.com/Strider-CD/strider-gitlab/issues/92) 42 | * **package:** update superagent to version 3.6.0 ([#99](https://github.com/Strider-CD/strider-gitlab/issues/99)) ([8899ff8](https://github.com/Strider-CD/strider-gitlab/commit/8899ff866e751afb1ad900a14ca6eb897a6682a0)) 43 | * webhook endpoint ([4268b2c](https://github.com/Strider-CD/strider-gitlab/commit/4268b2cc31311276a01cf8fd9e1f0050ecca13a7)), closes [#54](https://github.com/Strider-CD/strider-gitlab/issues/54) 44 | 45 | ## 1.0.4 46 | 47 | Bugfixes: 48 | 49 | - fixed an issue if group name is changed in gitlab 50 | 51 | ## 1.0.3 52 | 53 | Features: 54 | 55 | - #4 56 | 57 | Bugfixes: 58 | 59 | - added gravatar requirement to package.json 60 | 61 | ## 1.0.2 62 | 63 | Bugfixes: 64 | 65 | - #2 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # strider-gitlab 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/Strider-CD/strider-gitlab.svg)](https://greenkeeper.io/) 4 | 5 | > Note: v2 works with Gitlab API v4 (current version) use v1 for Gitlab API v3 6 | 7 | This plugin provides seamless integration between [Strider](https://github.com/Strider-CD/strider) and [GitLab](https://github.com/gitlabhq/gitlabhq). It enables you to add GitLab repositories to Strider and it hooks up necessary webhooks in order to automatically test on commits. 8 | 9 | [![Build Status](https://travis-ci.org/Strider-CD/strider-gitlab.svg)](https://travis-ci.org/Strider-CD/strider-gitlab) 10 | 11 | ## Set Up 12 | 13 | 1. Install the plugin (can be done either from the Admin/Plugins section of the GUI or by running `bin/strider install gitlab`) 14 | 2. Click on your e-mail address in the top right corner of the GUI, then click "Account" 15 | 3. Click "GitLab" at the left of your screen 16 | 4. Add your information (the private token can be found in your account settings on GitLab) 17 | 5. Navigate to "Projects" in the Strider GUI. You should now see a tab with the name of your GitLab account 18 | 19 | ## Contributors 20 | 21 | - Martin Ericson (http://www.devbox.com) 22 | - [nodefourtytwo/strider-gitlab](https://github.com/nodefourtytwo/strider-gitlab) 23 | - [jonlil](https://github.com/jonlil) 24 | - [edy](https://github.com/edy) 25 | - [_others_](https://github.com/Strider-CD/strider-gitlab/graphs/contributors) 26 | 27 | ## License 28 | 29 | The MIT License (MIT) 30 | 31 | Copyright (c) 2014 Martin Ericson 32 | 33 | Permission is hereby granted, free of charge, to any person obtaining a copy 34 | of this software and associated documentation files (the "Software"), to deal 35 | in the Software without restriction, including without limitation the rights 36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 | copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in all 41 | copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 49 | SOFTWARE. 50 | -------------------------------------------------------------------------------- /config/accountConfig.html: -------------------------------------------------------------------------------- 1 |
2 | 9 |
10 | 15 |
16 |
17 | 18 |
19 | 26 |
27 | 28 |
29 |
30 | 31 |
32 | 36 |
37 | 38 |
39 | 40 |
41 | -------------------------------------------------------------------------------- /config/config.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Caching

5 | 9 |
10 |
11 |
12 |

Service Hooks

13 |

14 | Service Hooks are the means by which gitlab notifies strider of new 15 | commits and pull requests to your repository. 16 |

17 |

18 | We already registered the requisite hooks when you added this project, but 19 | if you want to remove them or add them back, you can do so here. 20 |

21 | 28 | 31 | 32 |
33 |
34 | -------------------------------------------------------------------------------- /config/config.js: -------------------------------------------------------------------------------- 1 | app.controller('GitLabCtrl', [ 2 | '$scope', 3 | function ($scope) { 4 | $scope.config = $scope.providerConfig(); 5 | $scope.config.cache = $scope.config.cache || false; 6 | 7 | $scope.addWebhooks = function () { 8 | $scope.loadingWebhooks = true; 9 | $.ajax($scope.api_root + 'gitlab/hook', { 10 | type: 'POST', 11 | success: function () { 12 | $scope.loadingWebhooks = false; 13 | $scope.success('Set gitlab webhooks', true); 14 | }, 15 | error: function () { 16 | $scope.loadingWebhooks = false; 17 | $scope.error('Failed to set gitlab webhooks', true); 18 | }, 19 | }); 20 | }; 21 | 22 | $scope.deleteWebhooks = function () { 23 | $scope.loadingWebhooks = true; 24 | $.ajax($scope.api_root + 'gitlab/hook', { 25 | type: 'DELETE', 26 | success: function (data) { 27 | $scope.loadingWebhooks = false; 28 | $scope.success(data, true); 29 | }, 30 | error: function () { 31 | $scope.loadingWebhooks = false; 32 | $scope.error('Failed to remove gitlab webhooks', true); 33 | }, 34 | }); 35 | }; 36 | 37 | $scope.save = function () { 38 | this.providerConfig(this.config); 39 | }; 40 | }, 41 | ]); 42 | -------------------------------------------------------------------------------- /lib/api.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const async = require('async'); 4 | const superagent = require('superagent'); 5 | const debug = require('debug')('strider-gitlab:api'); 6 | const util = require('util'); 7 | const parseLinkHeader = require('parse-link-header'); 8 | 9 | module.exports = { 10 | get: get, 11 | parseRepo: parseRepo, 12 | createHooks: createHooks, 13 | deleteHooks: deleteHooks, 14 | addDeployKey: addDeployKey, 15 | removeDeployKey: removeDeployKey, 16 | }; 17 | 18 | /** 19 | * Retrieve a file from a GitLab repository, using the GitLab API. 20 | * @param {Object} config The configuration of the GitLab provider plugin. 21 | * @param {String} uri The URI of the file to retrieve. 22 | * @param {Function} done A function to call, once a result is available. 23 | */ 24 | function get(config, uri, done) { 25 | // If the configuration has no GitLab API URL, bail. 26 | if (!config.api_url) { 27 | return done( 28 | new Error('API URL missing from GitLab provider configuration!') 29 | ); 30 | } 31 | // Append a slash to the URL if there isn't one. 32 | let apiBase = config.api_url; 33 | if (!/\/$/.test(apiBase)) { 34 | apiBase += '/'; 35 | } 36 | // Construct the complete request URL 37 | const url = apiBase + uri; 38 | superagent 39 | .get(url) 40 | .query({ 41 | private_token: config.api_key, 42 | per_page: 100, 43 | membership: config.membership, 44 | }) 45 | .set('User-Agent', 'StriderCD (http://stridercd.com)') 46 | .end((error, res) => { 47 | res = res || {}; 48 | 49 | if (error) { 50 | return done(error, null, null); 51 | } 52 | 53 | debug(`Response body type: ${typeof res.body}`); 54 | debug( 55 | `Response body received: ${util.inspect(res.body, false, 10, true)}` 56 | ); 57 | if (res.text) { 58 | debug( 59 | `Response text received: ${util.inspect(res.text, false, 10, true)}` 60 | ); 61 | } 62 | if (res.error) { 63 | return done(res.error, null, res); 64 | } 65 | if (!res.body) { 66 | return done(undefined, res.body, res); 67 | } 68 | 69 | let results = res.body; 70 | 71 | if (res.headers.link) { 72 | const linkHeader = parseLinkHeader(res.headers.link); 73 | const numberOfPages = 74 | linkHeader && linkHeader.last ? linkHeader.last.page : 1; 75 | let i = 1; 76 | 77 | async.whilst( 78 | () => { 79 | return i < numberOfPages; 80 | }, 81 | (callback) => { 82 | i++; 83 | superagent 84 | .get(url) 85 | .query({ 86 | private_token: config.api_key, 87 | per_page: 100, 88 | page: i, 89 | }) 90 | .set('User-Agent', 'StriderCD (http://stridercd.com)') 91 | .end((err1, res) => { 92 | if (err1) return callback(err1); 93 | 94 | results = results.concat(res.body); 95 | callback(null, i); 96 | }); 97 | }, 98 | (err) => { 99 | if (err) return done(err); 100 | 101 | return done(null, results, res); 102 | } 103 | ); 104 | } else { 105 | return done(null, results, res); 106 | } 107 | }); 108 | } 109 | 110 | function parseRepo(repo) { 111 | return { 112 | id: repo.id, 113 | name: repo.path_with_namespace, 114 | display_name: repo.path_with_namespace, 115 | display_url: repo.web_url, 116 | group: repo.namespace.path, 117 | private: !repo.public, 118 | config: { 119 | auth: { type: 'ssh' }, 120 | scm: 'git', 121 | url: repo.ssh_url_to_repo, 122 | owner: repo.owner, 123 | repo: repo.web_url, 124 | pull_requests: 'none', 125 | whitelist: [], 126 | }, 127 | }; 128 | } 129 | 130 | function createHooks(config, repo_id, url, callback) { 131 | const endpoint_url = `${config.api_url}/projects/${repo_id}/hooks`; 132 | 133 | superagent 134 | .post(endpoint_url) 135 | .send({ 136 | url: url, 137 | push_events: true, 138 | }) 139 | .set('PRIVATE-TOKEN', config.api_key) 140 | .set('User-Agent', 'StriderCD (http://stridercd.com)') 141 | .end((err, res) => { 142 | if (err) return callback(err); 143 | if (res.status === 200) { 144 | debug( 145 | 'API request succeeded, but resource was not created. User possibly has insufficient access rights or GitLab API URL was not configured with correct prefix.' 146 | ); 147 | } 148 | if (res && res.status !== 201) return callback(res); 149 | 150 | return callback(null, true); 151 | }); 152 | } 153 | 154 | function deleteHooks(config, repo_id, url, callback) { 155 | const endpoint_url = `${config.api_url}/projects/${repo_id}/hooks`; 156 | 157 | // Fetch all webhooks from Gitlab 158 | superagent 159 | .get(endpoint_url) 160 | .set('PRIVATE-TOKEN', config.api_key) 161 | .set('User-Agent', 'StriderCD (http://stridercd.com)') 162 | .end((err, res) => { 163 | let deleted = false; 164 | 165 | if (err) { 166 | return callback(err); 167 | } 168 | 169 | if (!res) { 170 | return callback(new Error('Empty response.')); 171 | } 172 | 173 | async.each( 174 | res.body, 175 | (hook, cb) => { 176 | // Remove all webhooks matching url 177 | if (hook.url === url) { 178 | const hook_url = `${endpoint_url}/${hook.id}`; 179 | 180 | superagent 181 | .del(hook_url) 182 | .set('PRIVATE-TOKEN', config.api_key) 183 | .end((err) => { 184 | deleted = true; 185 | cb(err); 186 | }); 187 | } else cb(); 188 | }, 189 | (err) => { 190 | callback(err, deleted); 191 | } 192 | ); 193 | }); 194 | } 195 | 196 | function addDeployKey(config, repo_id, title, key, callback) { 197 | const endpoint_url = `${config.api_url}/projects/${encodeURIComponent( 198 | repo_id 199 | )}/deploy_keys`; 200 | 201 | superagent 202 | .post(endpoint_url) 203 | .send({ 204 | title: title, 205 | key: key, 206 | }) 207 | .set('User-Agent', 'StriderCD (http://stridercd.com)') 208 | .set('PRIVATE-TOKEN', config.api_key) 209 | .end((err, res) => { 210 | if (err) return callback(err); 211 | if (res.status === 200) { 212 | debug( 213 | 'API request succeeded, but resource was not created. User possibly has insufficient access rights or GitLab API URL was not configured with correct prefix.' 214 | ); 215 | } 216 | if (res && res.status !== 201) return callback(res); 217 | 218 | return callback(null, true); 219 | }); 220 | } 221 | 222 | function removeDeployKey(config, repo_id, title, callback) { 223 | const endpoint_url = `${config.api_url}/projects/${repo_id}/deploy_keys`; 224 | 225 | // Fetch all deploy keys from Gitlab 226 | superagent 227 | .get(endpoint_url) 228 | .set('PRIVATE-TOKEN', config.api_key) 229 | .set('User-Agent', 'StriderCD (http://stridercd.com)') 230 | .end((err, res) => { 231 | if (err) { 232 | return callback(err); 233 | } 234 | 235 | let deleted = false; 236 | 237 | if (!res) { 238 | return callback(new Error('Empty response.')); 239 | } 240 | 241 | async.each( 242 | res.body, 243 | (key, cb) => { 244 | // Remove all webhooks matching url 245 | if (key.title === title) { 246 | const deploy_key_url = `${endpoint_url}/${key.id}`; 247 | 248 | superagent 249 | .del(deploy_key_url) 250 | .set('PRIVATE-TOKEN', config.api_key) 251 | .end((err) => { 252 | deleted = true; 253 | cb(err); 254 | }); 255 | } else cb(); 256 | }, 257 | (err) => callback(err, deleted) 258 | ); 259 | }); 260 | } 261 | -------------------------------------------------------------------------------- /lib/webapp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const api = require('./api'); 5 | const async = require('async'); 6 | const debug = require('debug')('strider-gitlab:webapp'); 7 | const hostname = process.env.strider_server_name || 'http://localhost:3000'; 8 | const util = require('util'); 9 | const webhooks = require('./webhooks'); 10 | 11 | module.exports = { 12 | // this is the project-level config 13 | // project.provider.config 14 | config: { 15 | url: String, 16 | owner: String, 17 | repo: String, 18 | cache: Boolean, 19 | pull_requests: { type: String, enum: ['all', 'none', 'whitelist'] }, 20 | whitelist: [ 21 | { 22 | name: String, 23 | level: { type: String, enum: ['tester', 'admin'] }, 24 | }, 25 | ], 26 | // used for the webhook 27 | secret: String, 28 | // type: https || ssh 29 | auth: {}, 30 | }, 31 | 32 | listRepos: (config, done) => { 33 | api.get(config, 'projects', (err, repos) => { 34 | if (err) return done(err); 35 | 36 | if (!repos) { 37 | return done( 38 | new Error( 39 | 'Could not get a list of projects from the GitLab repository. Please check the configuration in Account->GitLab.' 40 | ) 41 | ); 42 | } 43 | 44 | // Parse and filter only git repos 45 | done( 46 | null, 47 | repos.map(api.parseRepo).filter((repo) => { 48 | return repo.config.scm === 'git'; 49 | }) 50 | ); 51 | }); 52 | }, 53 | 54 | getFile: (filename, ref, account, config, project, done) => { 55 | const repoId = project.provider.repo_id; 56 | const branch = encodeURIComponent(ref.branch); 57 | const encodedFileName = encodeURIComponent(filename); 58 | const uri = util.format( 59 | 'projects/%d/repository/blobs/%s?filepath=%s', 60 | repoId, 61 | branch, 62 | encodedFileName 63 | ); 64 | 65 | api.get(account, uri, (err, data, res) => { 66 | if (err) { 67 | return done(err, null); 68 | } else { 69 | done(err, res.text); 70 | } 71 | }); 72 | }, 73 | 74 | getBranches: (account, config, project, done) => { 75 | const repoId = project.provider.repo_id; 76 | const uri = util.format('projects/%d/repository/branches', repoId); 77 | 78 | debug(`Getting URI ${uri}`); 79 | api.get(account, uri, (err, branches) => { 80 | debug( 81 | `We get the following as branches: ${util.inspect( 82 | branches, 83 | false, 84 | 10, 85 | true 86 | )}` 87 | ); 88 | 89 | done( 90 | err, 91 | _.map(branches || [], (branch) => { 92 | return branch.name; 93 | }) 94 | ); 95 | }); 96 | }, 97 | 98 | // will be namespaced under /:org/:repo/api/gitlab 99 | routes: (app, context) => { 100 | app.post('/hook', (req, res) => { 101 | const url = `${hostname}/${req.project.name}/api/gitlab/webhook`; 102 | const config = req.accountConfig(); 103 | 104 | if (!config.api_key) 105 | return res.status(400).send('Gitlab account not configured'); 106 | 107 | return api.createHooks( 108 | config, 109 | req.project.provider.repo_id, 110 | url, 111 | (err) => { 112 | if (err) return res.status(500).send(err.message); 113 | 114 | return res.status(200).send('Webhook registered'); 115 | } 116 | ); 117 | }); 118 | 119 | app.delete('/hook', (req, res) => { 120 | const url = `${hostname}/${req.project.name}/api/gitlab/webhook`; 121 | const config = req.accountConfig(); 122 | 123 | if (!config.api_key) 124 | return res.status(400).send('Gitlab account not configured'); 125 | 126 | return api.deleteHooks( 127 | config, 128 | req.project.provider.repo_id, 129 | url, 130 | (err, deleted) => { 131 | if (err) return res.status(500).send(err.message); 132 | 133 | return res 134 | .status(200) 135 | .send(deleted ? 'Webhook removed' : 'No webhook to delete'); 136 | } 137 | ); 138 | }); 139 | 140 | // gitlab should hit this endpoint 141 | app.anon.post('/webhook', function (req, res) { 142 | webhooks.receiveWebhook(context.emitter, req, res); 143 | }); 144 | }, 145 | 146 | setupRepo: (account, config, project, done) => { 147 | const url = `${hostname}/${project.name}/api/gitlab/webhook`; 148 | const deploy_key_title = util.format('strider-%s', project.name); 149 | 150 | if (!account.api_key) 151 | return done(new Error('Gitlab account not configured')); 152 | 153 | // Create webhooks and add deploykey 154 | return async.parallel( 155 | [ 156 | (callback) => { 157 | debug('Creating webhooks...'); 158 | api.createHooks(account, project.provider.repo_id, url, callback); 159 | }, 160 | (callback) => { 161 | debug('Adding deployment keys...'); 162 | api.addDeployKey( 163 | account, 164 | project.provider.repo_id, 165 | deploy_key_title, 166 | project.branches[0].pubkey, 167 | callback 168 | ); 169 | }, 170 | ], 171 | (err) => { 172 | done(err, config); 173 | } 174 | ); 175 | }, 176 | 177 | teardownRepo: (account, config, project, done) => { 178 | const url = `${hostname}/${project.name}/api/gitlab/webhook`; 179 | const deploy_key_title = util.format('strider-%s', project.name); 180 | 181 | if (!account.api_key) 182 | return done(new Error('Gitlab account not configured')); 183 | 184 | // Remove webhooks and deploykey 185 | return async.parallel( 186 | [ 187 | (callback) => { 188 | api.deleteHooks(account, project.provider.repo_id, url, callback); 189 | }, 190 | (callback) => { 191 | api.removeDeployKey( 192 | account, 193 | project.provider.repo_id, 194 | deploy_key_title, 195 | callback 196 | ); 197 | }, 198 | ], 199 | done 200 | ); 201 | }, 202 | }; 203 | -------------------------------------------------------------------------------- /lib/webhooks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const debug = require('debug')('strider-gitlab:webhooks'); 4 | const gravatar = require('gravatar'); 5 | const util = require('util'); 6 | 7 | module.exports = { 8 | receiveWebhook: receiveWebhook, 9 | pushJob: pushJob, 10 | }; 11 | 12 | function makeJob(project, config) { 13 | var deploy = false; 14 | var branch = project.branch(config.branch) || { 15 | active: true, 16 | mirror_master: true, 17 | deploy_on_green: false, 18 | }; 19 | 20 | if (!branch.active) return false; 21 | 22 | if (config.branch !== 'master' && branch.mirror_master) { 23 | // mirror_master branches don't deploy 24 | deploy = false; 25 | } else { 26 | deploy = config.deploy && branch.deploy_on_green; 27 | } 28 | 29 | return { 30 | type: deploy ? 'TEST_AND_DEPLOY' : 'TEST_ONLY', 31 | trigger: config.trigger, 32 | project: project.name, 33 | ref: config.ref, 34 | plugin_data: config.plugin_data || {}, 35 | user_id: project.creator._id, 36 | created: new Date(), 37 | }; 38 | } 39 | 40 | function startFromCommit(project, payload, send) { 41 | const config = pushJob(payload); 42 | if (payload.commits) { 43 | const lastCommit = payload.commits[payload.commits.length - 1]; 44 | 45 | if (lastCommit.message.indexOf('[skip ci]') > -1) { 46 | return { skipCi: true }; 47 | } 48 | } else if (payload.after && /^0+$/.test(payload.after)) { 49 | // Tag push event reaction from tags added or removed 50 | // When reaction from `remove`, `payload.after` hash is all 0 51 | return { deleteTag: true }; 52 | } 53 | 54 | var branch = project.branch(config.branch); 55 | var job; 56 | 57 | if (branch) { 58 | job = makeJob(project, config); 59 | if (job) return send(job); 60 | } 61 | 62 | return false; 63 | } 64 | 65 | // returns : {trigger, branch, deploy} 66 | function pushJob(payload) { 67 | let branchname; 68 | let commit; 69 | if (payload.commits) { 70 | commit = payload.commits[payload.commits.length - 1]; 71 | 72 | if (!commit || !commit.author) { 73 | debug( 74 | "Unable to determine author from provided commit (may it's a merge commit?). Skipping" 75 | ); 76 | debug(`Commit data extracted from payload:${util.inspect(commit)}`); 77 | return null; 78 | } 79 | } else if (payload.after) { 80 | // If data haven't commits array but basic information to start ci exist 81 | commit = { 82 | url: `${payload.repository.homepage}/commit/${payload.after}`, 83 | message: 'tag push', 84 | timestamp: new Date().toISOString(), 85 | author: { 86 | name: payload.user_name || '', 87 | email: undefined, 88 | image: '', 89 | }, 90 | }; 91 | } else { 92 | return null; 93 | } 94 | 95 | let trigger; 96 | let ref; 97 | var isTagPush = false; 98 | 99 | if (payload.ref.indexOf('refs/heads/') === 0) { 100 | branchname = payload.ref.substring('refs/heads/'.length); 101 | ref = { 102 | branch: branchname, 103 | id: payload.after, 104 | }; 105 | } else if (payload.ref.indexOf('refs/tags/') === 0) { 106 | // `tag` ref is start with refs/tags/ 107 | // Git clone options can set `--branch tag-name` to clone `tag` same as clone `branch` 108 | isTagPush = true; 109 | branchname = payload.ref.substring('refs/tags/'.length); 110 | ref = { 111 | branch: branchname, 112 | id: payload.after, 113 | }; 114 | } else { 115 | ref = { 116 | fetch: payload.ref, 117 | }; 118 | } 119 | 120 | trigger = { 121 | type: isTagPush ? 'tag push' : 'commit', 122 | author: { 123 | name: commit.author.name, 124 | username: commit.author.username, 125 | email: commit.author.email, 126 | image: gravatar.url(commit.author.email, {}, true), 127 | }, 128 | url: commit.url, 129 | message: commit.message, 130 | timestamp: commit.timestamp, 131 | source: { 132 | type: 'plugin', 133 | plugin: 'gitlab', 134 | }, 135 | }; 136 | 137 | return { 138 | branch: branchname, 139 | trigger: trigger, 140 | deploy: true, 141 | ref: ref, 142 | }; 143 | } 144 | 145 | function receiveWebhook(emitter, req, res) { 146 | var payload = req.body; 147 | 148 | res.sendStatus(204); 149 | 150 | var result = startFromCommit(req.project, payload, sendJob); 151 | 152 | if (result && result.skipCi) { 153 | debug('Skipping commit due to [skip ci] tag'); 154 | } else if (result && result.deleteTag) { 155 | debug('Skipping push due to delete tag event'); 156 | } else if (!result) { 157 | debug('webhook received, but no branches matched or branch is not active'); 158 | } 159 | 160 | function sendJob(job) { 161 | emitter.emit('job.prepare', job); 162 | return true; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /lib/worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const git = require('strider-git/worker'); 4 | 5 | module.exports = { 6 | init: (dirs, account, config, job, done) => { 7 | return done(null, { 8 | config: config, 9 | account: account, 10 | fetch: (context, done) => { 11 | module.exports.fetch(dirs.data, account, config, job, context, done); 12 | }, 13 | }); 14 | }, 15 | fetch: (dest, account, config, job, context, done) => { 16 | if (config.auth.type === 'https' && !config.auth.username) { 17 | config.auth.username = account.accessToken; 18 | config.auth.password = ''; 19 | } 20 | 21 | git.fetch(dest, config, job, context, done); 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strider-gitlab", 3 | "version": "2.0.0", 4 | "description": "A gitlab provider for strider", 5 | "scripts": { 6 | "test": "npm run lint && npm run tests", 7 | "lint": "eslint lib", 8 | "tests": "mocha -R spec test/", 9 | "release": "standard-version" 10 | }, 11 | "engines": { 12 | "node": ">=4.2" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/Strider-CD/strider-gitlab.git" 17 | }, 18 | "keywords": [ 19 | "git", 20 | "gitlab", 21 | "strider" 22 | ], 23 | "author": { 24 | "name": "Martin Ericson " 25 | }, 26 | "license": "MIT", 27 | "readmeFilename": "README.md", 28 | "strider": { 29 | "id": "gitlab", 30 | "title": "GitLab", 31 | "type": "provider", 32 | "hosted": true, 33 | "config": { 34 | "controller": "GitLabCtrl" 35 | }, 36 | "accountConfig": { 37 | "setupLink": "/account/#provider-gitlab", 38 | "template": "config/accountConfig.html" 39 | }, 40 | "webapp": "lib/webapp.js", 41 | "worker": "lib/worker.js", 42 | "inline_icon": "git-square" 43 | }, 44 | "devDependencies": { 45 | "eslint": "4.13.0", 46 | "expect.js": "~0.3.1", 47 | "mocha": "~3.5.3", 48 | "nock": "^10.0.0", 49 | "standard-version": "^7.1.0" 50 | }, 51 | "dependencies": { 52 | "async": "~2.6.0", 53 | "debug": "~2.6.0", 54 | "gravatar": "^1.6.0", 55 | "lodash": "~4.17.0", 56 | "parse-link-header": "^0.4.1", 57 | "proxyquire": "^1.7.11", 58 | "strider-git": "^1.0.0", 59 | "superagent": "~3.6.0" 60 | }, 61 | "bugs": { 62 | "url": "https://github.com/Strider-CD/strider-gitlab/issues" 63 | }, 64 | "homepage": "https://github.com/Strider-CD/strider-gitlab" 65 | } 66 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | strider-gitlab tests 2 | ==================== 3 | 4 | The tests use mocha for testing and [nock](https://github.com/pgte/nock) for mocking responses from a gitlab server. 5 | 6 | Start out by writing an outline of what you want to test by adding pending tests to a .js file in the test directory, 7 | (inside the appropriate describe blocks) 8 | 9 | like: 10 | 11 | ``` 12 | it('should do xyz when abc happens'); 13 | it('should do lmn when opq happens'); 14 | ... as many as necessary 15 | ``` 16 | 17 | Now running npm test will show your tests as "pending" and marked with a "-". 18 | 19 | Next, observe the "happy path", the existing behavior of the code by using util.inspect to log the parameters passed to 20 | the function to be tested when the codepath is run (ensure that the codepath is run by using the Strider web gui if needed), 21 | in order to understand what needs to be passed to the function you want to test in the test file. 22 | 23 | In order to sniff and record the http traffic so that you can create a nock mock of the gitlab server, 24 | use code similar to the following inside the codepath that you want to test: 25 | 26 | ``` 27 | In file lib/api.js ... 28 | 29 | var nock = require('nock'); 30 | ... 31 | 32 | //for example, inside the removeDeployKey function in lib/api.js 33 | var appendLogToFile = function(content) { 34 | fs.appendFile('/noderoot/gitlab_remove_deploykey.txt', content); 35 | }; 36 | 37 | nock.recorder.rec({ 38 | logging: appendLogToFile, 39 | }); 40 | ``` 41 | 42 | In the above example, the file gitlab_remove_deploykey.txt file will contain the statements generated by nock. 43 | 44 | Next write out the body of the pending tests, one at a time. 45 | After writing out the body of a test, do an 'npm test' run, with nock still recording. 46 | Before doing the npm test run, ensure that only the current describe() block is active by adding the .only suffix. 47 | Like so, 48 | ``` 49 | describe.only('parseRepo', function(){ 50 | it('should correctly parse repo information as received from gitlab server into a repo object'); 51 | it('should throw an error if it gets an empty parameter as repo ?'); 52 | ... 53 | 54 | ``` 55 | This will ensure that only the tests for functionality currently under consideration will be run. 56 | Also, mark all tests other than the current one to be inactive by changing the "it('should ..." to "xit('should ...". 57 | Else, you can ensure that only the current test is run by changing 'it(' to 'it.only(' 58 | 59 | Before the run, you must also comment out any code that asks nock to intercept calls - the usual place for which is in 60 | the before, after or beforeEach/afterEach blocks. For example, comment out all the lines inside the following blocks 61 | ``` 62 | before('Setup the mock gitlab server', function setupNock() { 63 | nock.cleanAll(); //remove all interceptors 64 | require('./mocks/gitlab_add_key.js')(); //pull in the mock code to simulate the server for this block 65 | }); 66 | 67 | after('Tear down mock Gitlab server', function tearDownNock() { 68 | nock.cleanAll(); //remove all interceptors 69 | }); 70 | ``` 71 | This will ensure that the actual interaction between our code and the gitlab server will be recorded by nock. 72 | Copy out the code generated by nock into a .js file in the mocks subdirectory (see existing files in mocks/ for example) 73 | 74 | Before moving on to writing the next test, empty out the file used by nock for recording, and mark the test already 75 | written with a "xit(" or a "it.skip(" 76 | 77 | After you are done with writing the tests, remove or comment out the nock.recorder.rec code so that nock stops recording. 78 | Then, enable all the tests in the block and enable/de-comment out the code that asks nock to 79 | disableNetConnect and mock, and re-run "npm test" to see all your tests run with the gitlab server mocked out of the picture. 80 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --timeout 5000 2 | -------------------------------------------------------------------------------- /test/mocks/gitlab_add_key.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Simulation of responses from server when we 5 | request the addition of a deploy key. 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | 18 | const nock = require('nock'); 19 | 20 | module.exports = function() { 21 | //-------------------------------------------------------------------------------------- 22 | //simulate a Created 201 response when we try to deploy ssh keys for a project 23 | nock('http://localhost:80') 24 | .post('/api/v3/projects/5/deploy_keys', { 25 | "title": "strider-stridertester/privproject1", 26 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/privproject1-stridertester@gmail.com\n" 27 | }) 28 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 29 | .reply(201, { 30 | "id": 12, 31 | "title": "strider-stridertester/privproject1", 32 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/privproject1-stridertester@gmail.com", 33 | "created_at": "2015-08-19T03:35:01.863Z" 34 | }, { 35 | server: 'nginx', 36 | date: 'Wed, 19 Aug 2015 03:35:01 GMT', 37 | 'content-type': 'application/json', 38 | 'content-length': '534', 39 | connection: 'close', 40 | status: '201 Created', 41 | etag: '"5a11f9a2bf20878df6e3de77364e297c"', 42 | 'cache-control': 'max-age=0, private, must-revalidate', 43 | 'x-request-id': '565d54e9-f03b-4077-8cf4-a93503060889', 44 | 'x-runtime': '0.099917' 45 | }); 46 | 47 | //-------------------------------------------------------------------------------------- 48 | //simulate a 400 Bad Request response when an invalid key is sent 49 | nock('http://localhost:80') 50 | .post('/api/v3/projects/5/deploy_keys', {"title": "strider-stridertester/privproject1", "key": "invalid-key"}) 51 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 52 | .reply(400, {"message": {"key": ["is invalid"], "fingerprint": ["cannot be generated"]}}, { 53 | server: 'nginx', 54 | date: 'Wed, 19 Aug 2015 04:35:26 GMT', 55 | 'content-type': 'application/json', 56 | 'content-length': '72', 57 | connection: 'close', 58 | status: '400 Bad Request', 59 | 'cache-control': 'no-cache', 60 | 'x-request-id': '907e7139-cb13-407a-864f-a91ce108e419', 61 | 'x-runtime': '0.054109' 62 | }); 63 | 64 | //-------------------------------------------------------------------------------------- 65 | //simulate a 401 Unauthorized response when invalid credentials are used 66 | nock('http://localhost:80') 67 | .post('/api/v3/projects/5/deploy_keys', { 68 | "title": "strider-stridertester/privproject1", 69 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/privproject1-stridertester@gmail.com\n" 70 | }) 71 | .query({"private_token": "zRtVsmeznn7ySatTrnra"}) 72 | .reply(401, {"message": "401 Unauthorized"}, { 73 | server: 'nginx', 74 | date: 'Wed, 19 Aug 2015 05:03:45 GMT', 75 | 'content-type': 'application/json', 76 | 'content-length': '30', 77 | connection: 'close', 78 | status: '401 Unauthorized', 79 | 'cache-control': 'no-cache', 80 | 'x-request-id': '282a2411-dd11-4026-90b3-8a36560c0512', 81 | 'x-runtime': '0.004726' 82 | }); 83 | 84 | //-------------------------------------------------------------------------------------- 85 | //simulate a 404 response when project could not be found 86 | nock('http://localhost:80') 87 | .post('/api/v3/projects/wrong%20repo%20id/deploy_keys', { 88 | "title": "strider-stridertester/privproject1", 89 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/privproject1-stridertester@gmail.com\n" 90 | }) 91 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 92 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 93 | server: 'nginx', 94 | date: 'Wed, 19 Aug 2015 05:25:00 GMT', 95 | 'content-type': 'application/json', 96 | 'transfer-encoding': 'chunked', 97 | connection: 'close', 98 | status: '404 Not Found', 99 | 'cache-control': 'no-cache', 100 | 'x-request-id': '2c64ae26-d7b1-4caf-8efd-300893dedf37', 101 | 'x-runtime': '0.005714', 102 | 'content-encoding': 'gzip' 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /test/mocks/gitlab_create_hooks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Simulation of responses from a server when we 5 | request the creation of hooks. 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | const nock = require('nock'); 18 | 19 | module.exports = function() { 20 | 21 | //-------------------------------------------------------------------------------------- 22 | //Simulate a 401 reply if api key is not sent 23 | nock('http://localhost:80') 24 | .post('/api/v3/projects/5/hooks', { 25 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 26 | "push_events": true 27 | }) 28 | .reply(401, {"message": "401 Unauthorized"}, { 29 | server: 'nginx', 30 | date: 'Fri, 21 Aug 2015 14:42:46 GMT', 31 | 'content-type': 'application/json', 32 | 'content-length': '30', 33 | connection: 'close', 34 | status: '401 Unauthorized', 35 | 'cache-control': 'no-cache', 36 | 'x-request-id': '052eafeb-0028-4e69-b951-95925efdc232', 37 | 'x-runtime': '0.004600' 38 | }); 39 | 40 | //-------------------------------------------------------------------------------------- 41 | //Simulate 201 replies when we request the addition of a new project 42 | //(adding hooks and keys) 43 | nock('http://localhost:80') 44 | .post('/api/v3/projects/5/hooks', { 45 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 46 | "push_events": true 47 | }) 48 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 49 | .reply(201, { 50 | "id": 18, 51 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 52 | "created_at": "2015-08-21T14:11:54.922Z", 53 | "project_id": 5, 54 | "push_events": true, 55 | "issues_events": false, 56 | "merge_requests_events": false, 57 | "tag_push_events": false 58 | }, { 59 | server: 'nginx', 60 | date: 'Fri, 21 Aug 2015 14:11:54 GMT', 61 | 'content-type': 'application/json', 62 | 'content-length': '235', 63 | connection: 'close', 64 | status: '201 Created', 65 | etag: '"3b0821c3d2fa5d74684be993bfba7805"', 66 | 'cache-control': 'max-age=0, private, must-revalidate', 67 | 'x-request-id': '0f470a71-564f-4dcc-ae1f-743b73c98473', 68 | 'x-runtime': '0.021008' 69 | }); 70 | 71 | nock('http://localhost:80') 72 | .post('/api/v3/projects/5/deploy_keys', { 73 | "title": "strider-stridertester/privproject1", 74 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5CS04M9YZAoOkl9suZuKdBR643lB9Kv2AigyqcCfljhnFK3tWPLEnlsLE7ZnunTC3VcPPesdC8MeWC95EvQgNGH6Y5oXrGcaxZKiVDunk4xxKpJQjzMbp753B4R7i28NyZVShCyYG0+wkqAYlJ4NFWn6PMEOouinY8Z3/JD/e9luq4QgyyrI9s+e7VWKBBof9f6FtaGWXwpaWt7Peud3/AWKkhPELQmDDBEcZ5jxFneLsO0KEQ3qqGlEhQbtYLblgjWvuekd0CAReyUNjyJQG+rfDyVVadAQNHiri7c8cj6Y766FdfRskCKiA7E5IPfnysUcRx8657u6DG4PC6guV stridertester/privproject1-stridertester@gmail.com\n" 75 | }) 76 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 77 | .reply(201, { 78 | "id": 22, 79 | "title": "strider-stridertester/privproject1", 80 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5CS04M9YZAoOkl9suZuKdBR643lB9Kv2AigyqcCfljhnFK3tWPLEnlsLE7ZnunTC3VcPPesdC8MeWC95EvQgNGH6Y5oXrGcaxZKiVDunk4xxKpJQjzMbp753B4R7i28NyZVShCyYG0+wkqAYlJ4NFWn6PMEOouinY8Z3/JD/e9luq4QgyyrI9s+e7VWKBBof9f6FtaGWXwpaWt7Peud3/AWKkhPELQmDDBEcZ5jxFneLsO0KEQ3qqGlEhQbtYLblgjWvuekd0CAReyUNjyJQG+rfDyVVadAQNHiri7c8cj6Y766FdfRskCKiA7E5IPfnysUcRx8657u6DG4PC6guV stridertester/privproject1-stridertester@gmail.com", 81 | "created_at": "2015-08-21T14:11:54.986Z" 82 | }, { 83 | server: 'nginx', 84 | date: 'Fri, 21 Aug 2015 14:11:55 GMT', 85 | 'content-type': 'application/json', 86 | 'content-length': '534', 87 | connection: 'close', 88 | status: '201 Created', 89 | etag: '"13f3437db289c9c485011a1201db884f"', 90 | 'cache-control': 'max-age=0, private, must-revalidate', 91 | 'x-request-id': '0e829475-9fda-458e-8b34-08c7e8c4c0f5', 92 | 'x-runtime': '0.099567' 93 | }); 94 | 95 | //-------------------------------------------------------------------------------------- 96 | //Simulate a 404 if we passed an incorrect repo id 97 | nock('http://localhost:80') 98 | .post('/api/v3/projects/invalid-repo/hooks', { 99 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 100 | "push_events": true 101 | }) 102 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 103 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 104 | server: 'nginx', 105 | date: 'Fri, 21 Aug 2015 14:47:42 GMT', 106 | 'content-type': 'application/json', 107 | 'transfer-encoding': 'chunked', 108 | connection: 'close', 109 | status: '404 Not Found', 110 | 'cache-control': 'no-cache', 111 | 'x-request-id': 'b35510b5-8f3b-434c-bc63-e77ed6a5dc74', 112 | 'x-runtime': '0.006681', 113 | 'content-encoding': 'gzip' 114 | }); 115 | 116 | //-------------------------------------------------------------------------------------- 117 | //Simulate a 400 if we passed a bad URL 118 | nock('http://localhost:80') 119 | .post('/api/v3/projects/5/hooks', {"url": false, "push_events": true}) 120 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 121 | .reply(400, {"message": "400 (Bad request) \"url\" not given"}, { 122 | server: 'nginx', 123 | date: 'Fri, 21 Aug 2015 14:52:41 GMT', 124 | 'content-type': 'application/json', 125 | 'content-length': '49', 126 | connection: 'close', 127 | status: '400 Bad Request', 128 | 'cache-control': 'no-cache', 129 | 'x-request-id': '823fd96a-3829-4dbe-b7ff-75ab89b50455', 130 | 'x-runtime': '0.010701' 131 | }); 132 | 133 | //-------------------------------------------------------------------------------------- 134 | //Simulate a 401 if wrong credentials were sent 135 | nock('http://localhost:80') 136 | .post('/api/v3/projects/5/hooks', { 137 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 138 | "push_events": true 139 | }) 140 | .query({"private_token": "zRtVsmeznn7ySatTrnra"}) 141 | .reply(401, {"message": "401 Unauthorized"}, { 142 | server: 'nginx', 143 | date: 'Fri, 21 Aug 2015 16:38:40 GMT', 144 | 'content-type': 'application/json', 145 | 'content-length': '30', 146 | connection: 'close', 147 | status: '401 Unauthorized', 148 | 'cache-control': 'no-cache', 149 | 'x-request-id': '0f3180af-8f43-495f-91fb-8455313eff9a', 150 | 'x-runtime': '0.004978' 151 | }); 152 | }; 153 | -------------------------------------------------------------------------------- /test/mocks/gitlab_delete_hooks_when_absent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Simulation of responses from server when we 5 | ask for deleting hooks when no hooks are present 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | const nock = require('nock'); 18 | 19 | module.exports = function() { 20 | //-------------------------------------------------------------------------------------- 21 | //Empty array as list of hooks in response 22 | nock('http://localhost:80') 23 | .get('/api/v3/projects/5/hooks') 24 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 25 | .reply(200, [], { 26 | server: 'nginx', 27 | date: 'Fri, 21 Aug 2015 16:08:18 GMT', 28 | 'content-type': 'application/json', 29 | 'content-length': '2', 30 | connection: 'close', 31 | status: '200 OK', 32 | link: '; rel="first", ; rel="last"', 33 | etag: '"d751713988987e9331980363e24189ce"', 34 | 'cache-control': 'max-age=0, private, must-revalidate', 35 | 'x-request-id': 'de64f599-b582-4bcb-b68d-552c2441028e', 36 | 'x-runtime': '0.019459' 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /test/mocks/gitlab_delete_hooks_when_present.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | 5 | These scenarios are mock responses from the server 6 | when we request the deletion of hooks, when registered 7 | hooks are present. 8 | 9 | nock will simulate a gitlab server running at 10 | localhost:80, where Strider Tester, a user is 11 | registered with the name "stridertester", and 12 | has been registered with api token - zRtVsmeznn7ySatTrnrp 13 | stridertester is an "owner" of a group named "testunion" 14 | and has admin access to three projects - 15 | testunion / unionproject1 16 | Strider Tester / pubproject1 17 | Strider Tester / privproject1 18 | 19 | */ 20 | const nock = require('nock'); 21 | module.exports = function() { 22 | 23 | /*-------------------------------------------------------------------------------------- 24 | Simulate responses from gitlab server when deleting multiple hooks associated with a 25 | repo - here, there are four hooks with IDs 18, 19, 20 and 21. NOTE: what if other 26 | software has registered hooks with the same repo? Perhaps what we should be doing is, 27 | keeping track of which hooks were registered by Strider, and delete only those. 28 | -------------------------------------------------------------------------------------- 29 | */ 30 | nock('http://localhost:80') 31 | .persist() 32 | .get('/api/v3/projects/5/hooks') 33 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 34 | .reply(200, ["1f8b0800000000000003c592c14ec4300c44ff25e76e13274db5cd777002a128db9a369025c5719703e2df09688584b8778f9e198ffc243f7c883809a7a1111b25e1c4c2bc3a29531e435a7261679452b230c50989b130925c295e56cacf3832c8b04639474ee124dff1b4e4fc221a311206c6c907ae955a813da8e341c31d74ce80b37d6b8dbaafb96b8bffbec1d6712b8bc70bbe72118e69c346c452362cbfe25348a5aa67a4193de15bf5f89fcb61f67faa7eb63e9b2babda8d55f74e776d6fccad5861d88fb57356b783829bb11e776385fac35d3b68bd3bebe317b6d31703b1030000"], { 35 | server: 'nginx', 36 | date: 'Fri, 21 Aug 2015 15:17:53 GMT', 37 | 'content-type': 'application/json', 38 | 'transfer-encoding': 'chunked', 39 | connection: 'close', 40 | status: '200 OK', 41 | link: '; rel="first", ; rel="last"', 42 | etag: 'W/"66dde97b2afc21eb28d09cea6cd938b5"', 43 | 'cache-control': 'max-age=0, private, must-revalidate', 44 | 'x-request-id': '6dadbbb0-79d7-440f-9cb7-e68ce8a29554', 45 | 'x-runtime': '0.519726', 46 | 'content-encoding': 'gzip' 47 | }); 48 | 49 | nock('http://localhost:80') 50 | .delete('/api/v3/projects/5/hooks/20') 51 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 52 | .reply(200, ["1f8b08000000000000038d8dc16ec2301044ff65cfa1761c4095bf83532f96932c89a989dddd757aa8faef1884901017aef366defc4118c11add40a1081666916c958a69f0714e2cb6d35a2b160a2392200b92ca14d64ce98483b4cae7a0a620d1f7ea17fb39a56f68e04eddd5bd6b6020f482a3f3521f8c6e771bfdb931eda1dd5ab3b766fbb1efbaaf3a2b797cabc7486b18f0a65f4a8cf5b0f0ec70c54518ac50c1060273417e84471fb9a667a4091de14f65f242c54fee49755f2d49f0d9f47f014f6dcfe639010000"], { 53 | server: 'nginx', 54 | date: 'Fri, 21 Aug 2015 15:17:53 GMT', 55 | 'content-type': 'application/json', 56 | 'transfer-encoding': 'chunked', 57 | connection: 'close', 58 | status: '200 OK', 59 | etag: 'W/"441a3588cef9fb94b7d512ef5e950ea7"', 60 | 'cache-control': 'max-age=0, private, must-revalidate', 61 | 'x-request-id': 'b694345c-e83b-4b65-ae85-08d4464f3c07', 62 | 'x-runtime': '0.025442', 63 | 'content-encoding': 'gzip' 64 | }); 65 | 66 | nock('http://localhost:80') 67 | .delete('/api/v3/projects/5/hooks/19') 68 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 69 | .reply(200, ["1f8b08000000000000038d8dc16ec2301044ff65cfa1b603918abf831317cb244b6230b1d95da787aaff8e41080971e975decc9b5f080358b36da050040b9348b64ac5d4fb382516bbd65a2b160a0392200b92ca14964ce984bd18e573506390e80fea070f534a6768e049dddddd35d0137ac1c179a90fad36dd4a7faf5ab3331bdb6e6cd77e6db5d9d759c9c3bf7a8cb4841e1ffab9c4580f0b4f0e179c85c10a156c203017e45778f4916b7a411ad1115e2b930f2a7e746faae76a4e82efa6bf1b8989ea2039010000"], { 70 | server: 'nginx', 71 | date: 'Fri, 21 Aug 2015 15:17:53 GMT', 72 | 'content-type': 'application/json', 73 | 'transfer-encoding': 'chunked', 74 | connection: 'close', 75 | status: '200 OK', 76 | etag: 'W/"a589536875f3986c7a8dbb852470a6b9"', 77 | 'cache-control': 'max-age=0, private, must-revalidate', 78 | 'x-request-id': 'f7ae7e88-4d88-4410-8fe3-e5f9e571d46c', 79 | 'x-runtime': '0.014732', 80 | 'content-encoding': 'gzip' 81 | }); 82 | 83 | nock('http://localhost:80') 84 | .delete('/api/v3/projects/5/hooks/18') 85 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 86 | .reply(200, ["1f8b08000000000000038d8dc16ec2301044ff65cfa1b60391c0dfd11317cb244b627063b3bb4e0f55ff1d831012e2c275decc9b3f080358b36da050040b9348b64ac5d4fb382516bbd65a2b160a0392200b92ca14964ce984bd18e573506390e80fea170f534a6768e041ddcddd35d0137ac1c179a90fad36dd4a6f57adf9361b6b8ced365fbbb6ddd759c9c3473d465a428f77fd5c62ac878527870bcec260850a3610980bf2333cfac835fd411ad1115e2a93372a7e742faac76a4e82afa6ff2bc45c0bae39010000"], { 87 | server: 'nginx', 88 | date: 'Fri, 21 Aug 2015 15:17:53 GMT', 89 | 'content-type': 'application/json', 90 | 'transfer-encoding': 'chunked', 91 | connection: 'close', 92 | status: '200 OK', 93 | etag: 'W/"833cfcd8b12696291ad963463ea5ec47"', 94 | 'cache-control': 'max-age=0, private, must-revalidate', 95 | 'x-request-id': 'f36e3cd5-2f64-4859-93b1-dde3d6c4863e', 96 | 'x-runtime': '0.014471', 97 | 'content-encoding': 'gzip' 98 | }); 99 | 100 | nock('http://localhost:80') 101 | .delete('/api/v3/projects/5/hooks/21') 102 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 103 | .reply(200, ["1f8b08000000000000038d8dc16ec2301044ff65cfa1b6138290bfa3272e964996c4d48dcdee3a3d54fd770c4248a817aef366defc4218c1b6a68142112ccc22d92a15d3e0e39c586ca7b5562c1446244116249529ac99d2190731cae7a0a620d11fd50f1ee794bea08107753777dfc040e80547e7a53eb4daf41bbddfb4e6d36c6d676cbffbe83b7da8b392c7b77a8cb48601effaa5c4580f0bcf0e575c84c10a156c203017e46778f2916bfa8d34a123bc5426ffa8f8c9bda81eab2509be9afeae07c9ee7a39010000"], { 104 | server: 'nginx', 105 | date: 'Fri, 21 Aug 2015 15:17:53 GMT', 106 | 'content-type': 'application/json', 107 | 'transfer-encoding': 'chunked', 108 | connection: 'close', 109 | status: '200 OK', 110 | etag: 'W/"3586f6e4865bead39cdd672bd35adf9a"', 111 | 'cache-control': 'max-age=0, private, must-revalidate', 112 | 'x-request-id': 'b73a0d0d-7cab-4c25-a364-237699b677c9', 113 | 'x-runtime': '0.519791', 114 | 'content-encoding': 'gzip' 115 | }); 116 | 117 | //-------------------------------------------------------------------------------------- 118 | //Simulate case when api_key is not provided 119 | nock('http://localhost:80') 120 | .get('/api/v3/projects/5/hooks') 121 | .reply(401, {"message": "401 Unauthorized"}, { 122 | server: 'nginx', 123 | date: 'Fri, 21 Aug 2015 16:02:41 GMT', 124 | 'content-type': 'application/json', 125 | 'content-length': '30', 126 | connection: 'close', 127 | status: '401 Unauthorized', 128 | 'cache-control': 'no-cache', 129 | 'x-request-id': '343536d3-1830-45de-a609-78d98844599c', 130 | 'x-runtime': '0.003969' 131 | }); 132 | 133 | //-------------------------------------------------------------------------------------- 134 | //Simulate case when invalid repo id is sent 135 | nock('http://localhost:80') 136 | .get('/api/v3/projects/invalid-repo/hooks') 137 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 138 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 139 | server: 'nginx', 140 | date: 'Fri, 21 Aug 2015 16:05:38 GMT', 141 | 'content-type': 'application/json', 142 | 'transfer-encoding': 'chunked', 143 | connection: 'close', 144 | status: '404 Not Found', 145 | 'cache-control': 'no-cache', 146 | 'x-request-id': '3b41f707-85d9-49cd-a052-bcdcd0180b20', 147 | 'x-runtime': '0.005461', 148 | 'content-encoding': 'gzip' 149 | }); 150 | 151 | //-------------------------------------------------------------------------------------- 152 | //Case when invalid credentials are sent 153 | nock('http://localhost:80') 154 | .get('/api/v3/projects/5/hooks') 155 | .query({"private_token": "zRtVsmeznn7ySatTrnra"}) 156 | .reply(401, {"message": "401 Unauthorized"}, { 157 | server: 'nginx', 158 | date: 'Fri, 21 Aug 2015 16:33:39 GMT', 159 | 'content-type': 'application/json', 160 | 'content-length': '30', 161 | connection: 'close', 162 | status: '401 Unauthorized', 163 | 'cache-control': 'no-cache', 164 | 'x-request-id': 'bbf03f1f-8c62-4b7c-9bb1-e1fbb3856411', 165 | 'x-runtime': '0.004745' 166 | }); 167 | }; 168 | -------------------------------------------------------------------------------- /test/mocks/gitlab_delete_key_when_absent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Here we simulate the response of the server when there 5 | no deploy keys registered in the project. 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | 17 | */ 18 | const nock = require('nock'); 19 | 20 | module.exports = function() { 21 | 22 | nock('http://localhost:80') 23 | .get('/api/v3/projects/5/deploy_keys') 24 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 25 | .reply(200, [], { 26 | server: 'nginx', 27 | date: 'Wed, 19 Aug 2015 07:44:07 GMT', 28 | 'content-type': 'application/json', 29 | 'content-length': '2', 30 | connection: 'close', 31 | status: '200 OK', 32 | etag: '"d751713988987e9331980363e24189ce"', 33 | 'cache-control': 'max-age=0, private, must-revalidate', 34 | 'x-request-id': '6335ed65-d224-42e7-bf6d-948559539f88', 35 | 'x-runtime': '0.015344' 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /test/mocks/gitlab_delete_project.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Simulate responses from server when we try to 5 | delete a project. 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | 18 | const nock = require('nock'); 19 | 20 | module.exports = function() { 21 | 22 | //-------------------------------------------------------------------------------------- 23 | //Simulate responses during a successful delete operation 24 | nock('http://localhost:80') 25 | .get('/api/v3/projects/5/deploy_keys') 26 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 27 | .reply(200, ["1f8b080000000000000375914b8fa2400084ffca84abe3740302e26991a73c544659d4cd66836d232d0fb1bb5570b2ff7d35d9cb1eb62e95aad4a192efc797400ec244d4de054e78858589c03825074c877f9d63c631052d25b7969e4f18715178174adcbfa6ac185296bd194f4de5f92333c51e49f62b5a466c4c5fb5115b374ac2540d41752a734c2173a792a6b68d28ad34b52f2278d1a2dd6e7d2cf9d8c52d2b46b96dccf083fbdab987eea0408113b941ea2f7d5d424a536c1534b6ad4cf2b05dcddcf69458ae978f5cffd2a669ba6ff00eceafcbade55da7614b48c969b35191db5f947902d2b06ee60b51be2730ec5a45d2a3c1c1ebf69e6f6138ebd9f95672ad32ecf9f5d69f10f556eb8ad58613c04e078cdf8e5a4e06f4ae3a6c7395b6345e786668aa7982880b2ea4b3133da795fcd8630f01d6a8b06ac896811a8278162c8ad5b5e8ca1105a1cd833275827e2d6bb9f368bb1a24b934c3aae5c42650f2689f176c1f2f756edf53bd3625ff1c9b9b512546d1e7f7e7e3f2d347e0f0f67f3effa2fb76ac33527da073fde48628ce383efccaf8139f04456508c743515f436d22cb1359f9186b7027fcfef90733edcd2b18020000"], { 28 | server: 'nginx', 29 | date: 'Wed, 19 Aug 2015 07:34:26 GMT', 30 | 'content-type': 'application/json', 31 | 'transfer-encoding': 'chunked', 32 | connection: 'close', 33 | status: '200 OK', 34 | etag: 'W/"6b396edfec74bfbd19e6db1f696be410"', 35 | 'cache-control': 'max-age=0, private, must-revalidate', 36 | 'x-request-id': 'd7010f79-a813-4e88-8b23-4b8adac5bc43', 37 | 'x-runtime': '0.026638', 38 | 'content-encoding': 'gzip' 39 | }); 40 | 41 | nock('http://localhost:80') 42 | .delete('/api/v3/projects/5/hooks/14') 43 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 44 | .reply(200, ["1f8b08000000000000038d8db14ec4301044ff65eb1c76081177fe0e2a1acb970c89c1c466771d0ac4bf63d009e944433b6fe6cd07c5995c7fd751e5448e56d5e28c49790a69cda26eb0d61a518e3358210a3685e35e383f63d2de8412cd123585b379c779cdf9853aba50ffed1e3b9a184131fba0ede1d6f6e3c11e0ffde9c1debb6170c37873b4a7c736ab65fe574fc07b9cf0a3df6a4aedb0caeab1635321a75cd15114a990dff0292469e92b788167bc35a67fa886c55fa92eab2d2bae4d9f5f95e44d6c39010000"], { 45 | server: 'nginx', 46 | date: 'Wed, 19 Aug 2015 07:34:26 GMT', 47 | 'content-type': 'application/json', 48 | 'transfer-encoding': 'chunked', 49 | connection: 'close', 50 | status: '200 OK', 51 | etag: 'W/"48100b28764f2de3fffabb9de2e5c741"', 52 | 'cache-control': 'max-age=0, private, must-revalidate', 53 | 'x-request-id': 'f3623d3d-af5f-4673-a0c8-568a3f5829cb', 54 | 'x-runtime': '0.019863', 55 | 'content-encoding': 'gzip' 56 | }); 57 | 58 | nock('http://localhost:80') 59 | .delete('/api/v3/projects/5/deploy_keys/17') 60 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 61 | .reply(200, ["1f8b08000000000000038c52c992a24014fc950eaeb65dc5be9c06651341a5d541bd74201652b288558582f3f38331276ff36ef95e664646e4fbc3e11367f0ea27d752447e5ea06ecbf2934b094a183afd248c333801f2f2186a635edf40d510454394bf34151eb841d69cfe8b57a07e30a2341f139a7c98c34cc4c53399f27d2ad82f6899913979adcdc8ba131cc44a00ca4b912102a93b1154a5a97961ad2a7d1ec29b1a1e0e9b73c1341735349732db9ca127f3d56b0fdd519ece9dd09dc7fecad78554aef3bd9c6ab695081eb2cb99db5cb696eb6592ebdf9a388e8f353ac045bbda5b5e3b091a8c0b46ea9d92bafd4d5e6c411c54f562c98b8f2d0cba4616f47074f2baa3e75b08ce7a7abd174c2d4d7bd1defb4b4abcf5a6a495e9cc61a703caee6735c323f2501cba6b853d8996de34982ad936c52eb8e1cedeea1929c5e7117929a0b502cb1aef29a8208866f365be6ef3ae9008086c362f6267de6f4435739e4d57816d26cc906239d114c85978cc727a8c563ab31fb15e4d05ff1a4d7752c987e1f7ef2171f1eda7e0f44119c1274418a20c11d0107c6fc8f58252c68fdf4ebfce5582cbaff45a0dfd32cc4af46aee9ff89df9663290335c9f11199cebd7d748a2a123031e0d2d3124edefac4c4dacd252acd28cacd24cac9281a9c8cc2a35cdcac4c0ca32cdcad2d0ca3211a8bfa03429273359c92a2d31a738b5160053bf1cd39c020000"], { 62 | server: 'nginx', 63 | date: 'Wed, 19 Aug 2015 07:34:26 GMT', 64 | 'content-type': 'application/json', 65 | 'transfer-encoding': 'chunked', 66 | connection: 'close', 67 | status: '200 OK', 68 | etag: 'W/"73e7baa6dacd78d9a403fb0391b6e4bb"', 69 | 'cache-control': 'max-age=0, private, must-revalidate', 70 | 'x-request-id': 'f60ad59d-8088-40d4-9358-37ff188ec374', 71 | 'x-runtime': '0.033622', 72 | 'content-encoding': 'gzip' 73 | }); 74 | 75 | //-------------------------------------------------------------------------------------- 76 | //simulate trying to delete a project when an incorrect repo id is specified 77 | nock('http://localhost:80') 78 | .get('/api/v3/projects/wrong%20repo%20id/deploy_keys') 79 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 80 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 81 | server: 'nginx', 82 | date: 'Wed, 19 Aug 2015 08:35:42 GMT', 83 | 'content-type': 'application/json', 84 | 'transfer-encoding': 'chunked', 85 | connection: 'close', 86 | status: '404 Not Found', 87 | 'cache-control': 'no-cache', 88 | 'x-request-id': '234fcd84-6d78-44fb-921f-0c613414671a', 89 | 'x-runtime': '0.005932', 90 | 'content-encoding': 'gzip' 91 | }); 92 | 93 | //-------------------------------------------------------------------------------------- 94 | //simulate 401 when wrong credentials are specified 95 | nock('http://localhost:80') 96 | .get('/api/v3/projects/5/deploy_keys') 97 | .query({"private_token": "zRtVsmeznn7ySatTrnra"}) 98 | .reply(401, {"message": "401 Unauthorized"}, { 99 | server: 'nginx', 100 | date: 'Sat, 22 Aug 2015 04:43:22 GMT', 101 | 'content-type': 'application/json', 102 | 'content-length': '30', 103 | connection: 'close', 104 | status: '401 Unauthorized', 105 | 'cache-control': 'no-cache', 106 | 'x-request-id': '404162fd-f217-4d03-a429-d08edd893921', 107 | 'x-runtime': '0.460579' 108 | }); 109 | }; 110 | -------------------------------------------------------------------------------- /test/mocks/gitlab_get.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | This file sets up mock responses as received from gitlab for each request fired 5 | during get operations. 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | 18 | const nock = require('nock'); 19 | 20 | module.exports = function() { 21 | nock('http://localhost:80') 22 | .get('/api/v3/projects') 23 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100"}) 24 | .reply(200, ["1f8b0800000000000003e5966d6f9b3010c7bf0af2eb94674862a9dabec3fa6a5d850c5c823702cc36a0aaea77df199c2c84e6a1daa44a9b9444e87c773eff7df7238f2f84e7842e1724079909de285e57849287824b0b3fcc6a44fd1d3265ed18af147e21b7d2674b15607d5182e720ac07900a84b4da4ac7ea4c1bd6962a4905abb20293ed9876c015c5b649c9a522f4f169419a362d7946e8869512168489ace01d6035c6d071c9535e72f59c94d04149a8bb205216492bca44d58980a6c6ec5bae3e57750e1d5558c8508433fc9aca3d1b3d70f342a9e624549ba8e30cd1cee5e81e521d8cfbdd1284db556c07e83da9c498939eab22d10eb26199f63aec6d39a38cfbda31a2614a8b789a489b2f249a4a8069b8942dc8042a96965a64255a147d07620ba8e44f5c53b3d59effe0a711b2e24d03c7bee6ba32014c419e30bc5ee2bb5e74e7aeeebcd5831b537f4923d7f6d7abaf584889dd90b04cf14edfec5bde6b1a2e6ddff7b5f790b51689ee526f54d58836766e7050faa0e16fcd8e4d755fc198a66acbd2247ebb5cac38f2ed78e9e902da263f77ac89dfb9f9d135585b51b78db5a985d540dd9460692bafb6961c67c8c68d58c7141384be90a1cf7495afaf7bf3d87b836d311e3cbe30b2c360ed271753bf7722c7deb86120fd2b13698ea74f0bc2c1817fe74c5e8b3f339567c3508ba10fb4ca6640a714d3172e4198b5491e5cd24d880d2715760436f9d0c470b8ba291ffabeb7b762bc543bab77cef8e8041b6c2cc85731e441eee35310876eb664ae17a7ee7abdfc24ef43f75bebba7e9cdf235f2bc533c42a768229ea4845dc5a1be718981e0aa1320d3248991be7992e49f9a148096918d9ebd58d48896810da61384cf431520c3e2648090f529fdebfd1edd4fc1b2d98ee02063d9706911dae822b5c99f84db972c4891106061b733e44333e6810eddfe69e26ce7bb1f0d75ed4274d2578f7675c9827b80d0c4771ff0419a6e7b9150dd3a83d1be6d6ab7098867c241dbc80466b7be9c5b7fde1086888effb20fc0fe8f0f40bfc3991d8f20b0000"], { 25 | server: 'nginx', 26 | date: 'Tue, 18 Aug 2015 14:32:30 GMT', 27 | 'content-type': 'application/json', 28 | 'transfer-encoding': 'chunked', 29 | connection: 'close', 30 | status: '200 OK', 31 | link: '; rel="first", ; rel="last"', 32 | etag: 'W/"29dc98e2063c4571f4a98da2b681bb60"', 33 | 'cache-control': 'max-age=0, private, must-revalidate', 34 | 'x-request-id': '374db4c9-de67-4408-b9e8-49651bf8a7f3', 35 | 'x-runtime': '0.616995', 36 | 'content-encoding': 'gzip' 37 | }); 38 | 39 | nock('http://localhost:80') 40 | .get('/api/v3/projects') 41 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100", "page": "1"}) 42 | .reply(200, ["1f8b0800000000000003e5966d6f9b3010c7bf0af2eb94674862a9dabec3fa6a5d850c5c823702cc36a0aaea77df199c2c84e6a1daa44a9b9444e87c773eff7df7238f2f84e7842e1724079909de285e57849287824b0b3fcc6a44fd1d3265ed18af147e21b7d2674b15607d5182e720ac07900a84b4da4ac7ea4c1bd6962a4905abb20293ed9876c015c5b649c9a522f4f169419a362d7946e8869512168489ace01d6035c6d071c9535e72f59c94d04149a8bb205216492bca44d58980a6c6ec5bae3e57750e1d5558c8508433fc9aca3d1b3d70f342a9e624549ba8e30cd1cee5e81e521d8cfbdd1284db556c07e83da9c498939eab22d10eb26199f63aec6d39a38cfbda31a2614a8b789a489b2f249a4a8069b8942dc8042a96965a64255a147d07620ba8e44f5c53b3d59effe0a711b2e24d03c7bee6ba32014c419e30bc5ee2bb5e74e7aeeebcd5831b537f4923d7f6d7abaf584889dd90b04cf14edfec5bde6b1a2e6ddff7b5f790b51689ee526f54d58836766e7050faa0e16fcd8e4d755fc198a66acbd2247ebb5cac38f2ed78e9e902da263f77ac89dfb9f9d135585b51b78db5a985d540dd9460692bafb6961c67c8c68d58c7141384be90a1cf7495afaf7bf3d87b836d311e3cbe30b2c360ed271753bf7722c7deb86120fd2b13698ea74f0bc2c1817fe74c5e8b3f339567c3508ba10fb4ca6640a714d3172e4198b5491e5cd24d880d2715760436f9d0c470b8ba291ffabeb7b762bc543bab77cef8e8041b6c2cc85731e441eee35310876eb664ae17a7ee7abdfc24ef43f75bebba7e9cdf235f2bc533c42a768229ea4845dc5a1be718981e0aa1320d3248991be7992e49f9a148096918d9ebd58d48896810da61384cf431520c3e2648090f529fdebfd1edd4fc1b2d98ee02063d9706911dae822b5c99f84db972c4891106061b733e44333e6810eddfe69e26ce7bb1f0d75ed4274d2578f7675c9827b80d0c4771ff0419a6e7b9150dd3a83d1be6d6ab7098867c241dbc80466b7be9c5b7fde1086888effb20fc0fe8f0f40bfc3991d8f20b0000"], { 43 | server: 'nginx', 44 | date: 'Tue, 18 Aug 2015 14:32:30 GMT', 45 | 'content-type': 'application/json', 46 | 'transfer-encoding': 'chunked', 47 | connection: 'close', 48 | status: '200 OK', 49 | link: '; rel="first", ; rel="last"', 50 | etag: 'W/"29dc98e2063c4571f4a98da2b681bb60"', 51 | 'cache-control': 'max-age=0, private, must-revalidate', 52 | 'x-request-id': '374db4c9-de67-4408-b9e8-49651bf8a7f3', 53 | 'x-runtime': '0.616995', 54 | 'content-encoding': 'gzip' 55 | }); 56 | 57 | //mocks a response when incorrect credentials are specified 58 | nock('http://localhost:80') 59 | .get('/api/v3/projects') 60 | .query({"private_token": "zRtVsmeznn7ySatTrnra", "per_page": "100"}) 61 | .reply(401, {"message": "401 Unauthorized"}, { 62 | server: 'nginx', 63 | date: 'Wed, 19 Aug 2015 01:09:38 GMT', 64 | 'content-type': 'application/json', 65 | 'content-length': '30', 66 | connection: 'close', 67 | status: '401 Unauthorized', 68 | 'cache-control': 'no-cache', 69 | 'x-request-id': '4eb8c9f8-3a0c-4b70-aa9a-cfd61ea15b87', 70 | 'x-runtime': '0.444739' 71 | }); 72 | 73 | //mocks a response when an incorrect path is specified 74 | nock('http://localhost:80') 75 | .get('/api/v3/nonexistentpath') 76 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100"}) 77 | .reply(404, ["1f8b08000000000000039551b152c3300cddf315c24b61a9e9b5639a053816383a74615462a5f6c5b173b6c291bf4771e00358ec93a5f7f4de737df7fcf174fdbcbc80e5d13755fd77119aa602a8d9b1a7e66a0926bc112c71de25021fe3e0c20dfa98a08bb3371022434bf2300703f7a7c7d343ad37eccae25d18c026eacf4a674676ddbecb59c148c6e159e52e11050589bc14bc78ca968815f032d159317db32ef35a146a5bb455751bcd5234da43230ba571d8cae33ff5ee057adca0493608e3d4bce3409067f1cae21d8d499433b82c7653a28e01c5275be4d22fd958cc61c730c62f324239fd325d3c6126c10546c14982095e1dbf612bb4a30b2e734296205dbf36856f0d4bceb20e61940111b331d67a732d8acb7ffd000988a5bfc0010000"], { 78 | server: 'nginx', 79 | date: 'Wed, 19 Aug 2015 01:21:43 GMT', 80 | 'content-type': 'text/html; charset=utf-8', 81 | 'transfer-encoding': 'chunked', 82 | connection: 'close', 83 | status: '404 Not Found', 84 | 'x-frame-options': 'DENY', 85 | 'x-xss-protection': '1; mode=block', 86 | 'x-content-type-options': 'nosniff', 87 | 'x-ua-compatible': 'IE=edge', 88 | 'cache-control': 'no-cache', 89 | 'x-request-id': '78eec92b-b96f-49bb-a46f-3b9ed7d8ff71', 90 | 'x-runtime': '0.077683', 91 | 'content-encoding': 'gzip' 92 | }); 93 | }; 94 | -------------------------------------------------------------------------------- /test/mocks/gitlab_webapp_getbranches.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Here we simulate the response of the server when asked 5 | to get a list of branches from the privproject1 repo 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | 17 | privproject has two branches firstbranch and master 18 | */ 19 | 20 | const nock = require('nock'); 21 | 22 | module.exports = function() { 23 | 24 | //-------------------------------------------------------------------------------------- 25 | //Simulate a good response that sends the correct branches 26 | nock('http://localhost:80') 27 | .get('/api/v3/projects/5/repository/branches') 28 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100"}) 29 | .reply(200, ["1f8b0800000000000003bd914f4f023110c5bf0ae95520fdb74bdb9346397a516e48c8b49d42137631dd723084ef6e1102c68872d1ebbc99f732ef37dd92161a24868498ba6c13b46e49fac4ad9b266662b624fa22faa0400826a5422aaa5a680ca09c730a3c30e625b35450a145b96cb0eb60b177bc5f42bb40df7b1adf3d3c8e878d7f698bfe0a09db3c8fbe23664a24ad9d05ad99b3b606ea18adb50e0e2d528e4e0b1194ac2b2fc9ac4f609397eb847eee21effd3965d580aa01e71356994a19560d29a537541b4a4bd2617f7efcef39a7e831f526d8654c67191b88abe2d61df4fc21df2ef6d36169e1d445be3ef8505eb1b9987ddef82d7e571a4beb8caee4131360d5e1ae7f82d6c0f1992fbcaeaef5332ff0bed0b2b185f4d60b7185dff01a8112bc70d1b5171c582d1843096847ca8f2cd5238bdc0685f8132fa6275c18ce8c90ffcbeb52f0dff1ca6983bbd93b8b937b0e65030000"], { 30 | server: 'nginx', 31 | date: 'Sat, 22 Aug 2015 07:32:10 GMT', 32 | 'content-type': 'application/json', 33 | 'transfer-encoding': 'chunked', 34 | connection: 'close', 35 | status: '200 OK', 36 | etag: 'W/"a5766ebd98e6dcefebb0256942be9cf1"', 37 | 'cache-control': 'max-age=0, private, must-revalidate', 38 | 'x-request-id': '6166a894-b650-4e17-9057-6c23bc4e959f', 39 | 'x-runtime': '0.019611', 40 | 'content-encoding': 'gzip' 41 | }); 42 | 43 | //-------------------------------------------------------------------------------------- 44 | //Simulate a 401 when bad credentials are sent 45 | nock('http://localhost:80') 46 | .get('/api/v3/projects/5/repository/branches') 47 | .query({"private_token": "badkey", "per_page": "100"}) 48 | .reply(401, {"message": "401 Unauthorized"}, { 49 | server: 'nginx', 50 | date: 'Sat, 22 Aug 2015 07:45:55 GMT', 51 | 'content-type': 'application/json', 52 | 'content-length': '30', 53 | connection: 'close', 54 | status: '401 Unauthorized', 55 | 'cache-control': 'no-cache', 56 | 'x-request-id': 'c487af2c-3a4f-45ff-938e-9ee196429b65', 57 | 'x-runtime': '0.003879' 58 | }); 59 | 60 | //-------------------------------------------------------------------------------------- 61 | //Simulate a 404 when an invalid repo id of "invalidrepo" is sent 62 | //Heaven forbid that there actually is a project with repo ID "NaN" 63 | nock('http://localhost:80') 64 | .get('/api/v3/projects/NaN/repository/branches') 65 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100"}) 66 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 67 | server: 'nginx', 68 | date: 'Sat, 22 Aug 2015 07:56:44 GMT', 69 | 'content-type': 'application/json', 70 | 'transfer-encoding': 'chunked', 71 | connection: 'close', 72 | status: '404 Not Found', 73 | 'cache-control': 'no-cache', 74 | 'x-request-id': '60c9a1ef-0dbf-4533-8f6e-0aded176d319', 75 | 'x-runtime': '0.006694', 76 | 'content-encoding': 'gzip' 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /test/mocks/gitlab_webapp_getfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Here we simulate the response of the server when asked 5 | to get the strider.json file from the privproject1 repo 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | 18 | const nock = require('nock'); 19 | 20 | module.exports = function() { 21 | 22 | nock('http://localhost:80') 23 | .get('/api/v3/projects/5/repository/blobs/master') 24 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100", "filepath": "strider.json"}) 25 | .reply(200, ["1f8b0800000000000003abe6525050ca4bcc4d55b25250cacd2c294a54d2010915a726e7e7a580048b12cb3221622519994560a1e2d2a24aa8bab4fcd2a2920c90605246625ea912572d170048d47f8653000000"], { 26 | server: 'nginx', 27 | date: 'Wed, 19 Aug 2015 14:12:21 GMT', 28 | 'content-type': 'text/plain', 29 | 'transfer-encoding': 'chunked', 30 | connection: 'close', 31 | status: '200 OK', 32 | etag: 'W/"079e2a69978805f09ba55d6f6b3705f2"', 33 | 'cache-control': 'max-age=0, private, must-revalidate', 34 | 'x-request-id': 'daffad5d-cdff-4f23-bd2d-aec209109619', 35 | 'x-runtime': '0.013665', 36 | 'content-encoding': 'gzip' 37 | }); 38 | 39 | //-------------------------------------------------------------------------------------- 40 | //Simulate a scenario where the project does not contain a strider.json 41 | //For this purpose we have added another project named priproject2 with id 8 42 | nock('http://localhost:80') 43 | .get('/api/v3/projects/8/repository/blobs/master') 44 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100", "filepath": "strider.json"}) 45 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b2523231305170cbcc4955f0cb2f5170cb2fcd4b51aa0500db72e71020000000"], { 46 | server: 'nginx', 47 | date: 'Mon, 24 Aug 2015 06:28:17 GMT', 48 | 'content-type': 'application/json', 49 | 'transfer-encoding': 'chunked', 50 | connection: 'close', 51 | status: '404 Not Found', 52 | 'cache-control': 'no-cache', 53 | 'x-request-id': '9e221d4c-9109-4291-929b-2e7cb1e4f057', 54 | 'x-runtime': '0.022119', 55 | 'content-encoding': 'gzip' 56 | }); 57 | }; 58 | -------------------------------------------------------------------------------- /test/mocks/gitlab_webapp_listrepos.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Here we simulate the response of the server when asked 5 | to get a list of repositories from the gitlab server 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | 17 | */ 18 | 19 | const nock = require('nock'); 20 | 21 | module.exports = function() { 22 | 23 | //-------------------------------------------------------------------------------------- 24 | //Simulate a good response that sends the three correct repos 25 | nock('http://localhost:80') 26 | .get('/api/v3/projects') 27 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100"}) 28 | .reply(200, ["1f8b0800000000000003e5966d6f9b3010c7bf8ac5eb94e7474bd5f61dd657eb2ae4c0257823c06c03aaaa7ef79d816421340fd52655daa4248ace77e7f3df773f787c31786ed06865e42033c11bc5ebcaa0c643c125c10f238da8bf43a6c88ef14ae11772b27e26aa00f245099e83200f20150849da4ac7ea4c1bd6962a5d0b56650526db31ed802b8a6dd3924b65d0c7a795d1b4eb926706ddb052c2ca60222b780758cd64e8b8e46b5e72f59c96d04169507b654859a4ad285355a7029a1ab36fb9fa5cd539745461214311d6f03b55ee98e8819b174a3527a1da442d6b88b62e47f7b0d6c1b8df2d41b85dc57680deb34a2673da7355a4da41362cd35e87bd8935cab8af1d231aa6b488a789b4f942a2b90498864bd9824ca162eb528bac448ba2ef406c0195fc896b6ab1daf31ffc344256bc69e0d877baae4c005390a70cafd7706d27b8b3e33b277eb043ea4634b04d3789bf6221257643ca32c53b7db36f7927d48f4cd775b5f790b516a9ee52675475126dec5cefa0f441c3df9a1d9beabe82314dd596e594f8ed72b1e2c035c3c8d105b44d7eee5833bf73f3a36b205b51b70dd9d48234503725106de5d596c871864cdc88754c3161d01763e8335de5ebebde3cf6de605b8d070f2f8cec3058fbc9c5d4ef9dc8b1376e1848f7ca444ec7d3a70561e1c0bf7326afc59f99cab361a8c5d0075ae56940e714d3172e414c6bb33cb8a49b101b4e2aec086cf2a189e17075733ef47d6f6ec578a96656efacf1afe56db0b1208f43c8bddcc57f5ee8db59c46c275cdb49127d92f7befdadb56d37ccef91af95e21962153b612aea4845dc5a1b9718981f0aa1320f9a90b2342e335d92f24391e2533f3093f846a404d4f34ddf1f26fa1829133e6648f10f529fdeffa4dba9f9375a30dd050c3a36f502d38fbd2b5c99f9cdb972c48911061336967c08167cd020da3fcd1d4d9cf762e1af3da84f9a4af0eecfb8b04c701b188ee2fe0932cccf732b1ae6517b362cad57e1300ff9483a381e0d123372c22b2f1caeab5f4f8298baaee925d17f4087a75f735e9d4af20b0000"], { 29 | server: 'nginx', 30 | date: 'Sat, 22 Aug 2015 08:21:19 GMT', 31 | 'content-type': 'application/json', 32 | 'transfer-encoding': 'chunked', 33 | connection: 'close', 34 | status: '200 OK', 35 | link: '; rel="first", ; rel="last"', 36 | etag: 'W/"4568d3770abe645a4a67a538d64ae3d3"', 37 | 'cache-control': 'max-age=0, private, must-revalidate', 38 | 'x-request-id': '1f82c7d6-2948-487a-bbcd-9e2a485b4fb0', 39 | 'x-runtime': '0.089518', 40 | 'content-encoding': 'gzip' 41 | }); 42 | 43 | nock('http://localhost:80') 44 | .get('/api/v3/projects') 45 | .query({"private_token": "zRtVsmeznn7ySatTrnrp", "per_page": "100", "page": "1"}) 46 | .reply(200, ["1f8b0800000000000003e5966d6f9b3010c7bf8ac5eb94e7474bd5f61dd657eb2ae4c0257823c06c03aaaa7ef79d816421340fd52655daa4248ace77e7f3df773f787c31786ed06865e42033c11bc5ebcaa0c643c125c10f238da8bf43a6c88ef14ae11772b27e26aa00f245099e83200f20150849da4ac7ea4c1bd6962a5d0b56650526db31ed802b8a6dd3924b65d0c7a795d1b4eb926706ddb052c2ca60222b780758cd64e8b8e46b5e72f59c96d04169507b654859a4ad285355a7029a1ab36fb9fa5cd539745461214311d6f03b55ee98e8819b174a3527a1da442d6b88b62e47f7b0d6c1b8df2d41b85dc57680deb34a2673da7355a4da41362cd35e87bd8935cab8af1d231aa6b488a789b4f942a2b90498864bd9824ca162eb528bac448ba2ef406c0195fc896b6ab1daf31ffc344256bc69e0d877baae4c005390a70cafd7706d27b8b3e33b277eb043ea4634b04d3789bf6221257643ca32c53b7db36f7927d48f4cd775b5f790b516a9ee52675475126dec5cefa0f441c3df9a1d9beabe82314dd596e594f8ed72b1e2c035c3c8d105b44d7eee5833bf73f3a36b205b51b70dd9d48234503725106de5d596c871864cdc88754c3161d01763e8335de5ebebde3cf6de605b8d070f2f8cec3058fbc9c5d4ef9dc8b1376e1848f7ca444ec7d3a70561e1c0bf7326afc59f99cab361a8c5d0075ae56940e714d3172e414c6bb33cb8a49b101b4e2aec086cf2a189e17075733ef47d6f6ec578a96656efacf1afe56db0b1208f43c8bddcc57f5ee8db59c46c275cdb49127d92f7befdadb56d37ccef91af95e21962153b612aea4845dc5a1b9718981f0aa1320f9a90b2342e335d92f24391e2533f3093f846a404d4f34ddf1f26fa1829133e6648f10f529fdeffa4dba9f9375a30dd050c3a36f502d38fbd2b5c99f9cdb972c48911061336967c08167cd020da3fcd1d4d9cf762e1af3da84f9a4af0eecfb8b04c701b188ee2fe0932cccf732b1ae6517b362cad57e1300ff9483a381e0d123372c22b2f1caeab5f4f8298baaee925d17f4087a75f735e9d4af20b0000"], { 47 | server: 'nginx', 48 | date: 'Sat, 22 Aug 2015 08:21:19 GMT', 49 | 'content-type': 'application/json', 50 | 'transfer-encoding': 'chunked', 51 | connection: 'close', 52 | status: '200 OK', 53 | link: '; rel="first", ; rel="last"', 54 | etag: 'W/"4568d3770abe645a4a67a538d64ae3d3"', 55 | 'cache-control': 'max-age=0, private, must-revalidate', 56 | 'x-request-id': '1f82c7d6-2948-487a-bbcd-9e2a485b4fb0', 57 | 'x-runtime': '0.089518', 58 | 'content-encoding': 'gzip' 59 | }); 60 | 61 | //-------------------------------------------------------------------------------------- 62 | //Simulate a 401 on bad credentials being sent 63 | nock('http://localhost:80') 64 | .get('/api/v3/projects') 65 | .query({"private_token": "badkey", "per_page": "100"}) 66 | .reply(401, {"message": "401 Unauthorized"}, { 67 | server: 'nginx', 68 | date: 'Sat, 22 Aug 2015 08:32:44 GMT', 69 | 'content-type': 'application/json', 70 | 'content-length': '30', 71 | connection: 'close', 72 | status: '401 Unauthorized', 73 | 'cache-control': 'no-cache', 74 | 'x-request-id': '82e3262d-3a37-4a00-93c0-116b1886faf2', 75 | 'x-runtime': '0.004822' 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /test/mocks/gitlab_webapp_setuprepo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Here we simulate the response of the server when asked 5 | to setup the repo for privproject1 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | 17 | */ 18 | 19 | const nock = require('nock'); 20 | 21 | module.exports = function() { 22 | 23 | //-------------------------------------------------------------------------------------- 24 | //Simulate good response that are sent when the repo is set up correctly 25 | 26 | nock('http://localhost:80') 27 | .post('/api/v3/projects/5/hooks', { 28 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 29 | "push_events": true 30 | }) 31 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 32 | .reply(201, { 33 | "id": 23, 34 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 35 | "created_at": "2015-08-22T08:55:50.345Z", 36 | "project_id": 5, 37 | "push_events": true, 38 | "issues_events": false, 39 | "merge_requests_events": false, 40 | "tag_push_events": false 41 | }, { 42 | server: 'nginx', 43 | date: 'Sat, 22 Aug 2015 08:55:50 GMT', 44 | 'content-type': 'application/json', 45 | 'content-length': '235', 46 | connection: 'close', 47 | status: '201 Created', 48 | etag: '"3e1074f02f37c23c355cd1a33eecfb4b"', 49 | 'cache-control': 'max-age=0, private, must-revalidate', 50 | 'x-request-id': '3ccf26db-b72c-4b62-9b7b-42b307a85381', 51 | 'x-runtime': '0.031542' 52 | }); 53 | 54 | 55 | nock('http://localhost:80') 56 | .post('/api/v3/projects/5/deploy_keys', { 57 | "title": "strider-stridertester/privproject1", 58 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1j1c3wNyUwFzIhU5ELZb6tH1K+TkQgV0CrYjRvWmeZZr5aNKehSo5ntCoPtjZOddD2qYOUNyqe0EkdsSa7JeuD0blk5T9V8EADxqSmfYE8qD3Ch1JN0T4gbxoH20N45gqfpzug04FNwaDvCoxJgKvJXNj141SRLVVsa3DlByqC1Il+6TS7LqsQQMnSahgdx6fOUSLzSRG5NmbHGnS4CA1W4zyqQKzznh/Qj9WLxQKxugly3PPWtlcCDoaFBBQSOIgGVs00Bd3X8DJW/3gNPfydtUAdm/BcDZHOLyBUNOQCjR/fGyLS8D4ufYt6vr72No9O0dyKyI+FpOb+jPDG631 stridertester/privproject1-stridertester@gmail.com\n" 59 | }) 60 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 61 | .reply(201, { 62 | "id": 24, 63 | "title": "strider-stridertester/privproject1", 64 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1j1c3wNyUwFzIhU5ELZb6tH1K+TkQgV0CrYjRvWmeZZr5aNKehSo5ntCoPtjZOddD2qYOUNyqe0EkdsSa7JeuD0blk5T9V8EADxqSmfYE8qD3Ch1JN0T4gbxoH20N45gqfpzug04FNwaDvCoxJgKvJXNj141SRLVVsa3DlByqC1Il+6TS7LqsQQMnSahgdx6fOUSLzSRG5NmbHGnS4CA1W4zyqQKzznh/Qj9WLxQKxugly3PPWtlcCDoaFBBQSOIgGVs00Bd3X8DJW/3gNPfydtUAdm/BcDZHOLyBUNOQCjR/fGyLS8D4ufYt6vr72No9O0dyKyI+FpOb+jPDG631 stridertester/privproject1-stridertester@gmail.com", 65 | "created_at": "2015-08-22T08:55:50.403Z" 66 | }, { 67 | server: 'nginx', 68 | date: 'Sat, 22 Aug 2015 08:55:50 GMT', 69 | 'content-type': 'application/json', 70 | 'content-length': '534', 71 | connection: 'close', 72 | status: '201 Created', 73 | etag: '"f5843bd3736577d1059f9390612e8f81"', 74 | 'cache-control': 'max-age=0, private, must-revalidate', 75 | 'x-request-id': '667866c3-47bb-408c-9569-f049ab7a21e6', 76 | 'x-runtime': '0.103697' 77 | }); 78 | 79 | //-------------------------------------------------------------------------------------- 80 | //Simulate 401 unauthorized responses on sending incorrect api key 81 | 82 | nock('http://localhost:80') 83 | .post('/api/v3/projects/5/hooks', { 84 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 85 | "push_events": true 86 | }) 87 | .query({"private_token": "badkey"}) 88 | .reply(401, {"message": "401 Unauthorized"}, { 89 | server: 'nginx', 90 | date: 'Sat, 22 Aug 2015 09:47:00 GMT', 91 | 'content-type': 'application/json', 92 | 'content-length': '30', 93 | connection: 'close', 94 | status: '401 Unauthorized', 95 | 'cache-control': 'no-cache', 96 | 'x-request-id': 'f31bd5f2-36cf-4cd6-9199-7ca70831da4d', 97 | 'x-runtime': '0.004801' 98 | }); 99 | 100 | nock('http://localhost:80') 101 | .post('/api/v3/projects/5/deploy_keys', { 102 | "title": "strider-stridertester/privproject1", 103 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1j1c3wNyUwFzIhU5ELZb6tH1K+TkQgV0CrYjRvWmeZZr5aNKehSo5ntCoPtjZOddD2qYOUNyqe0EkdsSa7JeuD0blk5T9V8EADxqSmfYE8qD3Ch1JN0T4gbxoH20N45gqfpzug04FNwaDvCoxJgKvJXNj141SRLVVsa3DlByqC1Il+6TS7LqsQQMnSahgdx6fOUSLzSRG5NmbHGnS4CA1W4zyqQKzznh/Qj9WLxQKxugly3PPWtlcCDoaFBBQSOIgGVs00Bd3X8DJW/3gNPfydtUAdm/BcDZHOLyBUNOQCjR/fGyLS8D4ufYt6vr72No9O0dyKyI+FpOb+jPDG631 stridertester/privproject1-stridertester@gmail.com\n" 104 | }) 105 | .query({"private_token": "badkey"}) 106 | .reply(401, {"message": "401 Unauthorized"}, { 107 | server: 'nginx', 108 | date: 'Sat, 22 Aug 2015 09:47:00 GMT', 109 | 'content-type': 'application/json', 110 | 'content-length': '30', 111 | connection: 'close', 112 | status: '401 Unauthorized', 113 | 'cache-control': 'no-cache', 114 | 'x-request-id': '000fffa7-8aa6-46ed-a34a-7689f88d331f', 115 | 'x-runtime': '0.006122' 116 | }); 117 | 118 | //-------------------------------------------------------------------------------------- 119 | //Simulate 404 when invalid repo is specified 120 | nock('http://localhost:80') 121 | .post('/api/v3/projects/invalidrepo/hooks', { 122 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 123 | "push_events": true 124 | }) 125 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 126 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 127 | server: 'nginx', 128 | date: 'Sat, 22 Aug 2015 11:29:30 GMT', 129 | 'content-type': 'application/json', 130 | 'transfer-encoding': 'chunked', 131 | connection: 'close', 132 | status: '404 Not Found', 133 | 'cache-control': 'no-cache', 134 | 'x-request-id': '9d44eb7e-8a4d-4714-bd0a-5b4de958ed24', 135 | 'x-runtime': '0.005929', 136 | 'content-encoding': 'gzip' 137 | }); 138 | 139 | 140 | nock('http://localhost:80') 141 | .post('/api/v3/projects/invalidrepo/deploy_keys', { 142 | "title": "strider-stridertester/privproject1", 143 | "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1j1c3wNyUwFzIhU5ELZb6tH1K+TkQgV0CrYjRvWmeZZr5aNKehSo5ntCoPtjZOddD2qYOUNyqe0EkdsSa7JeuD0blk5T9V8EADxqSmfYE8qD3Ch1JN0T4gbxoH20N45gqfpzug04FNwaDvCoxJgKvJXNj141SRLVVsa3DlByqC1Il+6TS7LqsQQMnSahgdx6fOUSLzSRG5NmbHGnS4CA1W4zyqQKzznh/Qj9WLxQKxugly3PPWtlcCDoaFBBQSOIgGVs00Bd3X8DJW/3gNPfydtUAdm/BcDZHOLyBUNOQCjR/fGyLS8D4ufYt6vr72No9O0dyKyI+FpOb+jPDG631 stridertester/privproject1-stridertester@gmail.com\n" 144 | }) 145 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 146 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 147 | server: 'nginx', 148 | date: 'Sat, 22 Aug 2015 11:29:30 GMT', 149 | 'content-type': 'application/json', 150 | 'transfer-encoding': 'chunked', 151 | connection: 'close', 152 | status: '404 Not Found', 153 | 'cache-control': 'no-cache', 154 | 'x-request-id': 'f78f974c-207b-4d85-b42a-3c38dea668e7', 155 | 'x-runtime': '0.006760', 156 | 'content-encoding': 'gzip' 157 | }); 158 | 159 | 160 | //-------------------------------------------------------------------------------------- 161 | //Simulate a situation where an invalid ssh key is provided 162 | //the hook ends up getting created, but we get a 400 Bad Request when trying to add the key 163 | nock('http://localhost:80') 164 | .post('/api/v3/projects/5/hooks', { 165 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 166 | "push_events": true 167 | }) 168 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 169 | .reply(201, { 170 | "id": 27, 171 | "url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook", 172 | "created_at": "2015-08-22T11:31:48.159Z", 173 | "project_id": 5, 174 | "push_events": true, 175 | "issues_events": false, 176 | "merge_requests_events": false, 177 | "tag_push_events": false 178 | }, { 179 | server: 'nginx', 180 | date: 'Sat, 22 Aug 2015 11:31:48 GMT', 181 | 'content-type': 'application/json', 182 | 'content-length': '235', 183 | connection: 'close', 184 | status: '201 Created', 185 | etag: '"ae205f292720e19ab273c3bea2ba66b0"', 186 | 'cache-control': 'max-age=0, private, must-revalidate', 187 | 'x-request-id': '4562483b-5c3d-4f19-bf63-bb3968c39815', 188 | 'x-runtime': '0.023564' 189 | }); 190 | 191 | nock('http://localhost:80') 192 | .post('/api/v3/projects/5/deploy_keys', {"title": "strider-stridertester/privproject1", "key": "invalid key"}) 193 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 194 | .reply(400, {"message": {"key": ["is invalid"], "fingerprint": ["cannot be generated"]}}, { 195 | server: 'nginx', 196 | date: 'Sat, 22 Aug 2015 11:31:48 GMT', 197 | 'content-type': 'application/json', 198 | 'content-length': '72', 199 | connection: 'close', 200 | status: '400 Bad Request', 201 | 'cache-control': 'no-cache', 202 | 'x-request-id': 'be0ac084-2fae-4589-b4a7-13a65cc0f055', 203 | 'x-runtime': '0.074954' 204 | }); 205 | }; 206 | -------------------------------------------------------------------------------- /test/mocks/gitlab_webapp_teardownrepos.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Here we simulate the response of the server when asked 5 | to tear down the repo for privproject1 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | 17 | */ 18 | 19 | const nock = require('nock'); 20 | 21 | module.exports = function() { 22 | 23 | //-------------------------------------------------------------------------------------- 24 | //Simulate good responses that are sent when the repo is torn down correctly 25 | 26 | //get the list of ssh keys 27 | nock('http://localhost:80') 28 | .get('/api/v3/projects/5/deploy_keys') 29 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 30 | .reply(200, ["1f8b080000000000000375d14b8fa2401405e0bfd2614bdb4d953c5d0dcf26a2342f5b743299005542c94ba1046132ff7d3499cd2ce66e4eeec9d97ddf7f3104312b28bf3294d00a332ba6a71d41b85bfc4d8a7b8abbf74b47864bd79e714601f3ca94787a4efb62d1f5c98bfa386de9ce890ea60c9acfd7507d557bd6aaafd7ad939243efb53c053a98871d6756e7b477e429908b6242a6531feffa1859cb61107bc9abc7234621f59325f24814f6b3a7de2732d159b69348637349fa5aebb91b39bb6b3542f409e5ecd816bc1d8c72a1d73011344d833a1902a7d95a8dc8d9c04a63bfea14f3e6a54225dd907f4ed61f87d2deab8622679b496a8da54da3681b833054aa3db89bb9e5df3c944690cab59e69bb2c9725cb364ba4909087065b8fe6d05e9c2bab3a87c22c21328c4d75312d716d5b6c5e9ea6c93fef02a4ab2d7f307a711b70db36d8eecf208958019fc8e912eedf95358d2d213646a7ac9bf2ab41d7d80199a8ba568c58d4229bf65699ba3cdb7d2e371f6aa301bc9edd61d41af7e5ff3effd27dcbeb84546f595b3fdcb20e2714a39f097df0410e080b4e5e401801b0e2c51514de38513932bf7ffc014101a3c118020000"], { 31 | server: 'nginx', 32 | date: 'Sat, 22 Aug 2015 11:47:06 GMT', 33 | 'content-type': 'application/json', 34 | 'transfer-encoding': 'chunked', 35 | connection: 'close', 36 | status: '200 OK', 37 | etag: 'W/"690cd0366b746f11420cf4cd41447505"', 38 | 'cache-control': 'max-age=0, private, must-revalidate', 39 | 'x-request-id': '61269e5f-cfc1-422e-b74f-eca5a5171203', 40 | 'x-runtime': '0.019441', 41 | 'content-encoding': 'gzip' 42 | }); 43 | 44 | //get the list of hooks 45 | nock('http://localhost:80') 46 | .get('/api/v3/projects/5/hooks') 47 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 48 | .reply(200, ["1f8b0800000000000003658e4b0ec2300c44efe275216928bf9c83150845a1356d209062bbb040dc9d8010126239f3eca7d9dc21346027ba80812258e8447aab544cb58f5d62c9486bc542a141126441523d856b4fe980b594caf741b541a2dfa91beeba948e50404de8051be7252b8d2ea723bd1819b32a4b5bcdaca9c6cbb959e7bb8fc5bd364c731cb87378c5b33058a1010b08cc03f2b7dcfbc8b93d21b5e8082f99c91f15dfba1fd5fbebb17d0262c84f93ed000000"], { 49 | server: 'nginx', 50 | date: 'Sat, 22 Aug 2015 11:47:06 GMT', 51 | 'content-type': 'application/json', 52 | 'transfer-encoding': 'chunked', 53 | connection: 'close', 54 | status: '200 OK', 55 | link: '; rel="first", ; rel="last"', 56 | etag: 'W/"e7cde71ed4b2e2f010cc02aa14c300e5"', 57 | 'cache-control': 'max-age=0, private, must-revalidate', 58 | 'x-request-id': '27681ba4-9cea-4b26-8306-0ec64c76bfec', 59 | 'x-runtime': '0.022184', 60 | 'content-encoding': 'gzip' 61 | }); 62 | 63 | //delete the key associated with the project 64 | nock('http://localhost:80') 65 | .delete('/api/v3/projects/5/deploy_keys/28') 66 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 67 | .reply(200, ["1f8b08000000000000038c52c976a24014fd951cb6c4842a9957cd188e286132a29b1ca04a40c64009627ebef1f4ca5dbfdd7d77d8dcfb4b158892a1f84a5d07dc7f3f4073adaa572aed714c30fa8e0925539001dc8a1157108600c82c2f43ee8de1a513b5d83af45fba12cf4bd030e4ab7e885f94e5d4b5738f3530a7d078405df114f5f1563cad6eeda4380e6ecb12a081fbb8678cea920cb638fb629ecfc8b0ebd34d9b42733d8efc20b8f574c228205ebc466e1106c3dd556e733193bb68c5a14a6782f0b5d13227b4f73fd504d12714d3539bb3963f89b956c3985355156ac5e8dbcdce6c78c602661279552f195737e12ae18abc4bbcf93896d641d12531ddce42abaf2d1286bb080481541dc0cdc84cefeaa2248444acb554dda7992898965122a90858a8d3f5648c6d67ffd08a7dcc8d12225ddf569d61f21bcba4b3f23ccfde65ef234d69d9a33ef03b9fd9b5feee7001714873f85c9cbbe0f02e6d486472913ed965dd945f0dfa896c90f28a634688462db2c8609689c3d2fde77afba1342ac09bbb334e6ae3bc0ca42f10ee091e08eedfbbbe18bbbebde09480d513f527abe3a27a4bdb7ae99714a4c28fe6fe999f954f218bf85c3419ee97e4e6b19a98971920f3922c2c83817f6795966265996c65666a95626165666c656a62659c6695960452936461659a08d45f509a949399ac64959698539c5a0b00837af5d39c020000"], { 68 | server: 'nginx', 69 | date: 'Sat, 22 Aug 2015 11:47:06 GMT', 70 | 'content-type': 'application/json', 71 | 'transfer-encoding': 'chunked', 72 | connection: 'close', 73 | status: '200 OK', 74 | etag: 'W/"b4902d64c484b3f0e011862ecaa556eb"', 75 | 'cache-control': 'max-age=0, private, must-revalidate', 76 | 'x-request-id': '3e5e9625-a43c-4f32-a6a5-477e05b0ed3b', 77 | 'x-runtime': '0.023933', 78 | 'content-encoding': 'gzip' 79 | }); 80 | 81 | //delete the hook associated with the project 82 | nock('http://localhost:80') 83 | .delete('/api/v3/projects/5/hooks/30') 84 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 85 | .reply(200, ["1f8b08000000000000038d8dcd6ec2301084df65cf013be6aff573f4c4c532c93671ebc666771d0e8877c720540971e13adfcc3767083dd8956ea050040ba348b64ac5d4f93826968ab4562c147a244116249529cc99d20f76d22a9f831a82447f50273c8c29fd42030fea6eee4d031da117ec9d97fa6074bb59e88f85315f6d6bd75b6bd6cbcf9dd9d759c9fd5b3d469a438777fd5462ac87854787334ec260850a3610980bf27ff8ed23d7f40f69404778ac4c5ea8f8c13da91eab29093e9b2e57ff64dcac39010000"], { 86 | server: 'nginx', 87 | date: 'Sat, 22 Aug 2015 11:47:06 GMT', 88 | 'content-type': 'application/json', 89 | 'transfer-encoding': 'chunked', 90 | connection: 'close', 91 | status: '200 OK', 92 | etag: 'W/"cf8c92b71d0b72f1e754948cc93b78f1"', 93 | 'cache-control': 'max-age=0, private, must-revalidate', 94 | 'x-request-id': '55957387-e9bb-4b80-8172-2990bffbf2e0', 95 | 'x-runtime': '0.024064', 96 | 'content-encoding': 'gzip' 97 | }); 98 | 99 | //-------------------------------------------------------------------------------------- 100 | //Simulate 401 Unauthorized responses when invalid credentials are supplied 101 | 102 | nock('http://localhost:80') 103 | .get('/api/v3/projects/5/hooks') 104 | .query({"private_token": "badkey"}) 105 | .reply(401, {"message": "401 Unauthorized"}, { 106 | server: 'nginx', 107 | date: 'Sat, 22 Aug 2015 11:57:57 GMT', 108 | 'content-type': 'application/json', 109 | 'content-length': '30', 110 | connection: 'close', 111 | status: '401 Unauthorized', 112 | 'cache-control': 'no-cache', 113 | 'x-request-id': '8a4a34a5-f522-4f13-b7a5-534505e0a9c4', 114 | 'x-runtime': '0.004208' 115 | }); 116 | 117 | 118 | nock('http://localhost:80') 119 | .get('/api/v3/projects/5/deploy_keys') 120 | .query({"private_token": "badkey"}) 121 | .reply(401, {"message": "401 Unauthorized"}, { 122 | server: 'nginx', 123 | date: 'Sat, 22 Aug 2015 11:57:57 GMT', 124 | 'content-type': 'application/json', 125 | 'content-length': '30', 126 | connection: 'close', 127 | status: '401 Unauthorized', 128 | 'cache-control': 'no-cache', 129 | 'x-request-id': '1ebb7394-25f2-4279-abce-ea4845d458d5', 130 | 'x-runtime': '0.006446' 131 | }); 132 | 133 | //-------------------------------------------------------------------------------------- 134 | //Simulate a 404 when an invalid repo id is passed 135 | nock('http://localhost:80') 136 | .get('/api/v3/projects/invalidrepo/hooks') 137 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 138 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 139 | server: 'nginx', 140 | date: 'Sat, 22 Aug 2015 12:02:54 GMT', 141 | 'content-type': 'application/json', 142 | 'transfer-encoding': 'chunked', 143 | connection: 'close', 144 | status: '404 Not Found', 145 | 'cache-control': 'no-cache', 146 | 'x-request-id': '3af42422-6659-4deb-a356-857cc209dbe9', 147 | 'x-runtime': '0.005849', 148 | 'content-encoding': 'gzip' 149 | }); 150 | 151 | 152 | nock('http://localhost:80') 153 | .get('/api/v3/projects/invalidrepo/deploy_keys') 154 | .query({"private_token": "zRtVsmeznn7ySatTrnrp"}) 155 | .reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], { 156 | server: 'nginx', 157 | date: 'Sat, 22 Aug 2015 12:02:54 GMT', 158 | 'content-type': 'application/json', 159 | 'transfer-encoding': 'chunked', 160 | connection: 'close', 161 | status: '404 Not Found', 162 | 'cache-control': 'no-cache', 163 | 'x-request-id': '6a09637f-d80f-404b-a11c-80677a62a979', 164 | 'x-runtime': '0.006442', 165 | 'content-encoding': 'gzip' 166 | }); 167 | }; 168 | -------------------------------------------------------------------------------- /test/mocks/receive_webhooks_req.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //This is a mock for a request passed in to the receiveWebhooks function 4 | //It contains the payload received from the gitlab server in 5 | //body and project information from strider 6 | 7 | module.exports = { 8 | body: { 9 | object_kind: 'push', 10 | before: 'e85d185fdd17ebb379495f5ec14426134ce02837', 11 | after: '6a00c57e69bd4e269496ca27973191ecafcf8b20', 12 | ref: 'refs/heads/master', 13 | checkout_sha: '6a00c57e69bd4e269496ca27973191ecafcf8b20', 14 | message: null, 15 | user_id: 3, 16 | user_name: 'Strider Tester', 17 | user_email: 'stridertester@gmail.com', 18 | project_id: 5, 19 | repository: { 20 | name: 'privproject1', 21 | url: 'git@nodev:stridertester/privproject1.git', 22 | description: 'Test project 1.', 23 | homepage: 'http://nodev/stridertester/privproject1', 24 | git_http_url: 'http://nodev/stridertester/privproject1.git', 25 | git_ssh_url: 'git@nodev:stridertester/privproject1.git', 26 | visibility_level: 0 27 | }, 28 | commits: [{ 29 | id: '6a00c57e69bd4e269496ca27973191ecafcf8b20', 30 | message: 'testing webhook receiving\n', 31 | timestamp: '2015-08-26T21:25:22+09:00', 32 | url: 'http://nodev/stridertester/privproject1/commit/6a00c57e69bd4e269496ca27973191ecafcf8b20', 33 | author: {name: 'Strider Tester', email: 'stridertester@gmail.com'} 34 | }], 35 | total_commits_count: 1 36 | } 37 | , 38 | project: { 39 | name: "stridertester/privproject1", 40 | creator: { 41 | _id: "55d2ecb5edb0d634165eac37" 42 | }, 43 | branch: function(branchname) { 44 | //mocked to only return the master branch 45 | return { 46 | name: 'master', 47 | pubkey: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWHmPMdv+QDoR/vaPcu4yk/sn23B4wNQe3bGTtrIUjMj/7Ih3gy7XWGDUxCpVjTgq3LOfIK3Uu9cnHHV8KUQF7edF16MBMvZT2IsDgErXMEeWLYL7Or7yi6Oa9JGYSSxJXoKh8tMSqFooXFnppK9MtKCuuj2F537s9v/0fbL9WdIja5xMX0tDm7jGCSzMJhG7WYdzJ+GoX7Y9w+6JuWwTHIFavX8xVxJ59InxQ+GiHszibRcgnDUam3/QG9v/z9aeLNB7tngXX8NaszwAj1OA1sZnotmGrO0byH2zhcG7QPWYJkk94ZAz9TZMzEOqGze0Guh/A8VZOPRZjaWKKhx6B stridertester/privproject1-stridertester@gmail.com\n', 48 | privkey: '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEA1h5jzHb/kA6Ef72j3LuMpP7J9tweMDUHt2xk7ayFIzI/+yId\n4Mu11hg1MQqVY04KtyznyCt1LvXJxx1fClEBe3nRdejATL2U9iLA4BK1zBHli2C+\nzq+8oujmvSRmEksSV6CofLTEqhaKFxZ6aSvTLSgrro9hed+7Pb/9H2y/VnSI2ucT\nF9LQ5u4xgkszCYRu1mHcyfhqF+2PcPuiblsExyBWr1/MVcSefSJ8UPhoh7M4m0XI\nJw1Gpt/0Bvb/8/WnizQe7Z4F1/DWrM8AI9TgNbGZ6LZhqztG8h9s4XBu0D1mCZJP\neGQM/U2TMxDqhs3tBrofwPFWTj0WY2liiocegQIDAQABAoIBAE4yHwRG2SJFCwKT\nwUoVfFGtcxiiXqwAUeccwOdDwAOQkGkolnzIKIodoR9d3By+HY+z6JnjtRIHVT9Q\nbKsZ1k6/uE01STU9by9Mld+/NYFnb8ss88ILz/o20D13E4fOvs4dsCqK4d+0B45S\n+TV7ec3eA8XmOxUFLh5pBQn67w2lKmmslmQVdHovPifQLDrRLnmJs5WdS5FYFgGj\nVY4N1unyJ1a42YpcxDQgYYJilCrWtQ58L5FY2zE87y9p3uljxnBiFULuWdPIlWMq\nJ0cjp6IWlkl1lR7zfAIGK989VgNchcStZGRz3yGMnQYT7S20zEWX4MBkmQYUrbVf\nZ4xd9KECgYEA7JOJB1TEhRJPXPFW6uIWxz0INSHoDp4ue7TGvGhWouC7o7Ed+cdc\nbZL+Naqf34ZB9ZpPFxI9t2CDc3Xzb9jRlAja/kVAksojaJCXMqDuDtaCeUjpD5hh\ndQq3ZDF/B5aC67/1fOm++rv/ZusQt8yeo/RRYJSajb9AR5N9n8sHLnUCgYEA57LU\ntSNNAxRkucAkTooo0oEGg1GLae4JsyyFxQAkCE/YZUmZKfOhpPUhiqst9XhaI08o\n++/9hpE2DlQe2xfsvIxgIGlZDlEZCfRu9+sM0s7OWGSh+U/VXDAowczJwAnN48Js\nUKTuwBgQYuNXKk19y37omqHq0sxScWRe4izyhl0CgYAH0o0KYAQrfkJ/iT9dfuJP\n7jWyRA+/Q/23e2/C1RRgSFwL+pRKKQxmVyDut1iX9IGD1HlfAuxlftx52eGVxi6P\n3YcYN0P+Vo67K2TEeMvGU9N2nTGPoXM/gn4z4usXXiOwFeXRHo2BDuxQA9/GpA5u\nz2pNbjx6CWPfugHCYd037QKBgE3MuKvSHKvqDyBoKkjND4QPmxZBLWT2bv9g9dH+\niBraZLkuC2YQzrhLL2YWsKn6LZopnINsRF8JJ3OMP4gl8nIlWKnJdgPeq1+yWgiZ\nPocStirsL489hVEdQrJAh4YaRK4zvJcfqqOJ8Qaje8NSnejUxloWAHmj7hLxNwMP\nQKhpAoGAEt5A8mlohNoJAEJyoO0dH2m2oyBhxSGOhNdwE0GPMdOeDlLhkkn0JB+8\n+y9j+jCpjEpOfHkPZ7gVOkWgZUZwhbzYkDmfy8OXFuVUtUtDHvF7MoHGCXBsVpCq\nCuBauEVw5orSfYJXFwoFYwLbiXSVBdNVvNMsC6bDwi1J701SsOU=\n-----END RSA PRIVATE KEY-----\n', 49 | _id: "55dac66a7946e3a309c92f68", 50 | runner: {id: 'simple-runner', config: {pty: false}}, 51 | plugins: [{ 52 | id: 'node', 53 | enabled: true, 54 | config: {}, 55 | _id: "55dac66a7946e3a309c92f69", 56 | showStatus: true 57 | }], 58 | deploy_on_green: true, 59 | mirror_master: false, 60 | active: true 61 | } 62 | } 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /test/mocks/sample_payload.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | object_kind: 'push', 5 | before: '9be0948373aedbbed7ac6ce1da708061fac072d7', 6 | after: '352e6fe2ea42d394a21dc7995df2116e86bb0684', 7 | ref: 'refs/heads/master', 8 | checkout_sha: '352e6fe2ea42d394a21dc7995df2116e86bb0684', 9 | message: null, 10 | user_id: 3, 11 | user_name: 'Strider Tester', 12 | user_email: 'stridertester@gmail.com', 13 | project_id: 5, 14 | repository: { 15 | name: 'privproject1', 16 | url: 'git@nodev:stridertester/privproject1.git', 17 | description: 'Test project 1.', 18 | homepage: 'http://nodev/stridertester/privproject1', 19 | git_http_url: 'http://nodev/stridertester/privproject1.git', 20 | git_ssh_url: 'git@nodev:stridertester/privproject1.git', 21 | visibility_level: 0 22 | }, 23 | commits: [{ 24 | id: '378105b72465107d6ca8e6c70d88cb9b9b7fcbac', 25 | message: 'first commit\n', 26 | timestamp: '2015-08-26T20:01:10+09:00', 27 | url: 'http://nodev/stridertester/privproject1/commit/378105b72465107d6ca8e6c70d88cb9b9b7fcbac', 28 | author: {name: 'Strider Tester', email: 'stridertester@gmail.com'} 29 | }, 30 | { 31 | id: '352e6fe2ea42d394a21dc7995df2116e86bb0684', 32 | message: 'updated strider.json\n', 33 | timestamp: '2015-08-26T20:02:07+09:00', 34 | url: 'http://nodev/stridertester/privproject1/commit/352e6fe2ea42d394a21dc7995df2116e86bb0684', 35 | author: {name: 'Strider Tester', email: 'stridertester@gmail.com'} 36 | }], 37 | total_commits_count: 2 38 | }; 39 | -------------------------------------------------------------------------------- /test/mocks/sample_payload_tag_push_with_v7.x.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | ref: 'refs/tags/tag-1.1.2', 5 | before: '9be0948373aedbbed7ac6ce1da708061fac072d7', 6 | after: '352e6fe2ea42d394a21dc7995df2116e86bb0684', 7 | user_id: 3, 8 | user_name: 'Strider Tester', 9 | project_id: 1, 10 | repository: { 11 | name: 'privproject1', 12 | url: 'git@nodev:stridertester/privproject1.git', 13 | description: 'Test project 1.', 14 | homepage: 'http://nodev/stridertester/privproject1' 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /test/test_api.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | 5 | Used to test the gitlab API wrapper 6 | 7 | nock will simulate a gitlab server running at 8 | localhost:80, where Strider Tester, a user is 9 | registered with the name "stridertester", and 10 | has been registered with api token - zRtVsmeznn7ySatTrnrp 11 | stridertester is an "owner" of a group named "testunion" 12 | and has admin access to three projects - 13 | testunion / unionproject1 14 | Strider Tester / pubproject1 15 | Strider Tester / privproject1 16 | */ 17 | 18 | 19 | const expect = require('expect.js'); 20 | const api = require('../lib/api'); 21 | let util = require('util'); 22 | let debug = require('debug')('strider-gitlab:test:api'); 23 | const nock = require('nock'); 24 | 25 | const correctConfig = { 26 | api_key: 'zRtVsmeznn7ySatTrnrp', 27 | api_url: 'http://localhost:80/api/v3' 28 | }; 29 | 30 | const wrongCredentialsConfig = { 31 | api_key: 'zRtVsmeznn7ySatTrnra', 32 | api_url: 'http://localhost:80/api/v3' 33 | }; 34 | 35 | const invalidServerNameConfig = { 36 | api_key: 'zRtVsmeznn7ySatTrnrp', 37 | api_url: 'http://localghost:80/api/v3' 38 | }; 39 | 40 | const configWithoutApiUrl = {api_key: 'zRtVsmeznn7ySatTrnrp'}; 41 | 42 | const configWithoutApiKey = { 43 | api_url: 'http://localhost:80/api/v3' 44 | }; 45 | 46 | const correctDeployKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/privproject1-stridertester@gmail.com\n"; 47 | 48 | describe('gitlab api', function() { 49 | before('Setup the mock gitlab server', function setupNock() { 50 | nock.cleanAll(); 51 | require('./mocks/gitlab_get.js')(); 52 | require('./mocks/gitlab_add_key.js')(); 53 | }); 54 | 55 | after('Tear down mock Gitlab server', function tearDownNock() { 56 | nock.cleanAll(); 57 | }); 58 | 59 | //-------------------------------------------------------------------------------------- 60 | describe('get', function() { 61 | it('should get a list of projects', function(done) { 62 | api.get(correctConfig, 'projects', function(err, body, res) { 63 | expect(err).to.not.be.ok(); 64 | expect(body).to.be.an(Array); 65 | done(); 66 | }); 67 | }); 68 | 69 | it('should return an error if a non existent path is asked for', function(done) { 70 | 71 | const wrongPath = 'nonexistentpath'; 72 | 73 | api.get(correctConfig, wrongPath, function(err, body, res) { 74 | expect(err).to.be.ok(); 75 | expect(err).to.be.an(Error); 76 | expect(err.status).to.eql('404'); 77 | done(); 78 | }); 79 | }); 80 | 81 | it('should return a 401 error if incorrect credentials are specified', function(done) { 82 | api.get(wrongCredentialsConfig, 'projects', function(err, body, res) { 83 | expect(err).to.be.ok(); 84 | expect(err).to.be.an(Error); 85 | expect(err.status).to.eql('401'); 86 | done(); 87 | }); 88 | }); 89 | 90 | it('should return an error if the specified gitlab server IP cannot be resolved from the name', function(done) { 91 | api.get(invalidServerNameConfig, 'projects', function(err, body, res) { 92 | expect(err).to.be.ok(); 93 | expect(err).to.be.an(Error); 94 | done(); 95 | }); 96 | }); 97 | 98 | it('should return an error if the config passed in to it does not have a Gitlab API url', function(done) { 99 | const config = {api_key: 'zRtVsmeznn7ySatTrnrp'}; 100 | api.get(config, 'projects', function(err, body, res) { 101 | expect(err).to.be.ok(); 102 | expect(err).to.be.an(Error); 103 | done(); 104 | }); 105 | }); 106 | 107 | it('should invoke our callback with the first parameter as undefined if the Gitlab server responds with a falsy value for res.body'); 108 | }); 109 | 110 | //-------------------------------------------------------------------------------------- 111 | describe('parseRepo', function() { 112 | it('should correctly parse repo information as received from gitlab server into a repo object'); 113 | it('should throw an error if it gets an empty parameter as repo ?'); 114 | it('should throw an error if repo.id is absent ?'); 115 | it('should throw an error if repo.path_with_namespace is absent ?'); 116 | it('should throw an error if repo.web_url is absent ?'); 117 | it('should throw an error if repo.public is absent ?'); 118 | it('should throw an error if repo.ssh_url_to_repo is absent ?'); 119 | it('should throw an error if repo.owner is absent ?'); 120 | it('should throw an error if repo.web_url is absent ?'); 121 | 122 | /* 123 | return { 124 | 83 id: repo.id, 125 | 84 name: repo.path_with_namespace, 126 | 85 display_name: repo.path_with_namespace, 127 | 86 display_url: repo.web_url, 128 | 87 group: repo.namespace.path, 129 | 88 private: !repo.public, 130 | 89 config: { 131 | 90 auth: {type: 'ssh'}, 132 | 91 scm: 'git', 133 | 92 url: repo.ssh_url_to_repo, 134 | 93 owner: repo.owner, 135 | 94 repo: repo.web_url, 136 | 95 pull_requests: 'none', 137 | 96 whitelist: [] 138 | 97 } 139 | */ 140 | }); 141 | 142 | //-------------------------------------------------------------------------------------- 143 | describe('addDeployKey', function() { 144 | it('should return an error if any of its expected arguments are absent'); 145 | 146 | it('should invoke our callback with err as null and the second parameter as true, when given correct parameters', function(done) { 147 | api.addDeployKey(correctConfig, 5, 'strider-stridertester/privproject1', correctDeployKey, function(err, secondParam) { 148 | expect(err).to.not.be.ok(); 149 | expect(secondParam).to.be.ok(); 150 | done(); 151 | }); 152 | }); 153 | 154 | it('should give an error if invalid data is sent as an ssh key', function(done) { 155 | api.addDeployKey(correctConfig, 5, 'strider-stridertester/privproject1', "invalid-key", function(err, secondParam) { 156 | //debug("Err is: " + util.inspect(err, false, 10, true)); 157 | expect(err).to.be.ok(); 158 | done(); 159 | }); 160 | }); 161 | 162 | it('should give an error if incorrect credentials are passed to it', function(done) { 163 | api.addDeployKey(wrongCredentialsConfig, 5, 'strider-stridertester/privproject1', correctDeployKey, function(err, secondParam) { 164 | //debug("Err is: " + util.inspect(err, false, 10, true)); 165 | expect(err).to.be.ok(); 166 | done(); 167 | }); 168 | }); 169 | 170 | it('should return an error if the specified gitlab server IP cannot be resolved from the name', function(done) { 171 | api.addDeployKey(invalidServerNameConfig, 5, 'strider-stridertester/privproject1', correctDeployKey, function(err, secondParam) { 172 | expect(err).to.be.ok(); 173 | expect(err).to.be.an(Error); 174 | done(); 175 | }); 176 | }); 177 | 178 | it('should return an error if the config passed in to it does not have a Gitlab API url', function(done) { 179 | const config = {api_key: 'zRtVsmeznn7ySatTrnrp'}; 180 | api.addDeployKey(config, 5, 'strider-stridertester/privproject1', correctDeployKey, function(err, secondParam) { 181 | expect(err).to.be.ok(); 182 | expect(err).to.be.an(Error); 183 | done(); 184 | }); 185 | }); 186 | 187 | it('should give an error if invalid repo id is passed to it', function(done) { 188 | api.addDeployKey(correctConfig, "wrong repo id", 'strider-stridertester/privproject1', correctDeployKey, function(err, secondParam) { 189 | //debug("Err is: " + util.inspect(err, false, 10, true)); 190 | expect(err).to.be.ok(); 191 | done(); 192 | }); 193 | }); 194 | }); 195 | 196 | //-------------------------------------------------------------------------------------- 197 | describe('removeDeployKey - when key is registered with the server', function() { 198 | before('Setup the mock gitlab server', function setupNock() { 199 | nock.cleanAll(); 200 | require('./mocks/gitlab_delete_project.js')(); 201 | }); 202 | 203 | after('Tear down mock Gitlab server', function tearDownNock() { 204 | nock.cleanAll(); 205 | }); 206 | 207 | it('should return an error if any of its expected arguments are absent'); 208 | 209 | it('should delete a key and invoke our callback with err as null and wasDeleted as true when given correct parameters', function(done) { 210 | api.removeDeployKey(correctConfig, 5, 'strider-stridertester/privproject1', function(err, wasDeleted) { 211 | //debug("Err is: " + util.inspect(err, false, 10, true)); 212 | //debug("Err is: " + err); 213 | //debug("wasDeleted is: " + wasDeleted); 214 | expect(err).to.not.be.ok(); 215 | expect(wasDeleted).to.be.ok(); 216 | done(); 217 | }); 218 | }); 219 | 220 | it('should return an error if wrong credentials are given', function(done) { 221 | api.removeDeployKey(wrongCredentialsConfig, 5, 'strider-stridertester/privproject1', function(err, wasDeleted) { 222 | //debug("Err is: " + util.inspect(err, false, 10, true)); 223 | //debug("Err is: " + err); 224 | expect(err).to.be.ok(); 225 | expect(err).to.be.an(Error); 226 | done(); 227 | }); 228 | }); 229 | 230 | it('should return an error if the config passed in to it does not have a Gitlab API url', function(done) { 231 | api.removeDeployKey(configWithoutApiUrl, 5, 'strider-stridertester/privproject1', function(err, wasDeleted) { 232 | //debug("Err is: " + util.inspect(err, false, 10, true)); 233 | //debug("Err is: " + err); 234 | expect(err).to.be.ok(); 235 | expect(err).to.be.an(Error); 236 | done(); 237 | }); 238 | }); 239 | 240 | it('should return an error if the specified gitlab server IP cannot be resolved from the name', function(done) { 241 | api.removeDeployKey(invalidServerNameConfig, 5, 'strider-stridertester/privproject1', function(err, wasDeleted) { 242 | //Currently due to an issue with nock/superagent interaction we get a TypeError thrown instead of ENOTFOUND 243 | //https://github.com/pgte/nock/issues/211#issuecomment-133636234 244 | //debug("Err is: " + util.inspect(err, false, 10, true)); 245 | //debug("Err is: " + err.stack); 246 | expect(err).to.be.ok(); 247 | expect(err).to.be.an(Error); 248 | done(); 249 | }); 250 | }); 251 | 252 | it('should give an error if invalid repo id is passed to it', function(done) { 253 | api.removeDeployKey(correctConfig, "wrong repo id", 'strider-stridertester/privproject1', function(err, secondParam) { 254 | //debug("Err is: " + err); 255 | //debug("Err is: " + util.inspect(err, false, 10, true)); 256 | expect(err).to.be.ok(); 257 | done(); 258 | }); 259 | }); 260 | }); 261 | 262 | describe('removeDeployKey - when key is not registered in the gitlab server', function() { 263 | before('Setup the mock gitlab server', function setupNock() { 264 | nock.cleanAll(); 265 | require('./mocks/gitlab_delete_key_when_absent.js')(); 266 | }); 267 | 268 | after('Tear down mock Gitlab server', function tearDownNock() { 269 | nock.cleanAll(); 270 | }); 271 | 272 | it('should callback with err as null and wasDeleted as false', function(done) { 273 | api.removeDeployKey(correctConfig, 5, 'strider-stridertester/privproject1', function(err, wasDeleted) { 274 | //debug("Err is: " + util.inspect(err, false, 10, true)); 275 | //debug("wasDeleted is: " + wasDeleted); 276 | expect(err).to.not.be.ok(); 277 | expect(wasDeleted).to.not.be.ok(); 278 | done(); 279 | }); 280 | }); 281 | }); 282 | 283 | //-------------------------------------------------------------------------------------- 284 | describe('createHooks', function() { 285 | //takes parameters config, repo_id, url and callback 286 | 287 | beforeEach('Setup the mock gitlab server for creating hooks', function setupNock() { 288 | nock.cleanAll(); 289 | require('./mocks/gitlab_create_hooks.js')(); 290 | }); 291 | 292 | afterEach('Tear down mock Gitlab server', function tearDownNock() { 293 | nock.cleanAll(); 294 | }); 295 | 296 | 297 | it('should return true as the second parameter and err as false if hooks were created successfully', function(done) { 298 | api.createHooks(correctConfig, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, couldCreateHooks) { 299 | //debug("error: " + err + " couldCreateHooks: " + couldCreateHooks); 300 | expect(err).to.not.be.ok(); 301 | expect(couldCreateHooks).to.be.ok(); 302 | done(); 303 | }); 304 | });//NOTE: if the webhook has already been created, gitlab creates a new one with an incremented ID 305 | 306 | it('should callback with an error if config does not have an api_url', function(done) { 307 | api.createHooks(configWithoutApiUrl, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, couldCreateHooks) { 308 | expect(err).to.be.ok(); 309 | done(); 310 | }); 311 | }); 312 | 313 | it('should callback with an error if config does not have an api_key', function(done) { 314 | api.createHooks(configWithoutApiKey, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, couldCreateHooks) { 315 | expect(err).to.be.ok(); 316 | done(); 317 | }); 318 | }); 319 | 320 | it('should callback with an error if invalid credentials were specified', function(done) { 321 | api.createHooks(wrongCredentialsConfig, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, couldCreateHooks) { 322 | expect(err).to.be.ok(); 323 | done(); 324 | }); 325 | }); 326 | 327 | 328 | it('should callback with an error if an invalid repo_id was specified', function(done) { 329 | api.createHooks(correctConfig, 'invalid-repo', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, couldCreateHooks) { 330 | expect(err).to.be.ok(); 331 | done(); 332 | }); 333 | }); 334 | 335 | it('should callback with a 400 error if the URL parameter is not a string', function(done) { 336 | api.createHooks(correctConfig, '5', false, function(err, couldCreateHooks) { 337 | expect(err).to.be.ok(); 338 | done(); 339 | }); 340 | }); 341 | 342 | it('should callback with an error if the gitlab server cannot be reached or resolved', function(done) { 343 | api.createHooks(invalidServerNameConfig, '5', false, function(err, couldCreateHooks) { 344 | expect(err).to.be.ok(); 345 | done(); 346 | }); 347 | }); 348 | }); 349 | 350 | //-------------------------------------------------------------------------------------- 351 | describe('deleteHooks - when hook has been registered', function() { 352 | before('Setup the mock gitlab server', function setupNock() { 353 | nock.cleanAll(); 354 | require('./mocks/gitlab_delete_hooks_when_present.js')(); 355 | }); 356 | 357 | after('Tear down mock Gitlab server', function tearDownNock() { 358 | nock.cleanAll(); 359 | }); 360 | 361 | 362 | it('should call our callback with second param as true and err as null if hooks were successfully deleted', function(done) { 363 | api.deleteHooks(correctConfig, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, wasDeleted) { 364 | expect(err).to.not.be.ok(); 365 | expect(wasDeleted).to.be.ok(); 366 | done(); 367 | }); 368 | }); 369 | 370 | it('should callback with an error if config does not have an api_url', function(done) { 371 | api.deleteHooks(configWithoutApiUrl, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, wasDeleted) { 372 | //debug('Error is ' + util.inspect(err, false, null, true)); 373 | expect(err).to.be.ok(); 374 | done(); 375 | }); 376 | }); 377 | 378 | it('should callback with an error if config does not have an api_key', function(done) { 379 | api.deleteHooks(configWithoutApiKey, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, wasDeleted) { 380 | expect(err).to.be.ok(); 381 | done(); 382 | }); 383 | }); 384 | 385 | it('should callback with an error if invalid credentials were specified', function(done) { 386 | api.deleteHooks(wrongCredentialsConfig, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, wasDeleted) { 387 | expect(err).to.be.ok(); 388 | done(); 389 | }); 390 | }); 391 | 392 | 393 | it('should callback with an error if an invalid repo_id was specified', function(done) { 394 | api.deleteHooks(correctConfig, 'invalid-repo', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, wasDeleted) { 395 | expect(err).to.be.ok(); 396 | done(); 397 | }); 398 | }); 399 | 400 | 401 | it('should callback with an error if the gitlab server cannot be reached', function(done) { 402 | api.deleteHooks(invalidServerNameConfig, '5', 'http://localhost:3000/stridertester/privproject1/api/gitlab/webhook', function(err, wasDeleted) { 403 | expect(err).to.be.ok(); 404 | done(); 405 | }); 406 | }); 407 | }); 408 | 409 | //-------------------------------------------------------------------------------------- 410 | describe('deleteHooks - when hook has not been registered', function() { 411 | before('Setup the mock gitlab server', function setupNock() { 412 | nock.cleanAll(); 413 | require('./mocks/gitlab_delete_hooks_when_absent.js')(); 414 | }); 415 | 416 | after('Tear down mock Gitlab server', function tearDownNock() { 417 | nock.cleanAll(); 418 | }); 419 | 420 | it('should callback with err as null and wasDeleted as false', function(done) { 421 | api.deleteHooks(correctConfig, 5, 'strider-stridertester/privproject1', function(err, wasDeleted) { 422 | //debug("Err is: " + util.inspect(err, false, 10, true)); 423 | //debug("wasDeleted is: " + wasDeleted); 424 | expect(err).to.not.be.ok(); 425 | expect(wasDeleted).to.not.be.ok(); 426 | done(); 427 | }); 428 | }); 429 | }); 430 | }); 431 | -------------------------------------------------------------------------------- /test/test_webapp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Used to test the gitlab webapp 5 | 6 | nock will simulate a gitlab server running at 7 | localhost:80, where Strider Tester, a user is 8 | registered with the name "stridertester", and 9 | has been registered with api token - zRtVsmeznn7ySatTrnrp 10 | stridertester is an "owner" of a group named "testunion" 11 | and has admin access to three projects - 12 | testunion / unionproject1 13 | Strider Tester / pubproject1 14 | Strider Tester / privproject1 15 | */ 16 | 17 | const expect = require('expect.js'); 18 | const webapp = require('../lib/webapp'); 19 | const util = require('util'); 20 | const nock = require('nock'); 21 | 22 | function deepClone(sourceObject) { 23 | return JSON.parse(JSON.stringify(sourceObject)); 24 | } 25 | 26 | const wrongCredentialsConfig = { 27 | api_url: 'http://localhost:80/api/v3', 28 | api_key: 'badkey' 29 | }; 30 | 31 | const providerConfig = { 32 | whitelist: [], 33 | pull_requests: 'none', 34 | repo: 'http://nodev/stridertester/privproject1', 35 | owner: { 36 | avatar_url: 'http://www.gravatar.com/avatar/3f671ed86ed3d21ed3640c7a016b0997?s=40&d=identicon', 37 | state: 'active', 38 | id: 3, 39 | username: 'stridertester', 40 | name: 'Strider Tester' 41 | }, 42 | url: 'git@nodev:stridertester/privproject1.git', 43 | scm: 'git', 44 | auth: {type: 'ssh'} 45 | }; 46 | 47 | const providerConfigForProjectWithMissingStriderJson = 48 | { 49 | whitelist: [], 50 | pull_requests: 'none', 51 | repo: 'http://nodev/stridertester/priproject2', 52 | owner: { 53 | avatar_url: 'http://www.gravatar.com/avatar/3f671ed86ed3d21ed3640c7a016b0997?s=40&d=identicon', 54 | state: 'active', 55 | id: 3, 56 | username: 'stridertester', 57 | name: 'Strider Tester' 58 | }, 59 | url: 'git@nodev:stridertester/priproject2.git', 60 | scm: 'git', 61 | auth: {type: 'ssh'} 62 | }; 63 | 64 | const repoProject = { 65 | name: 'stridertester/privproject1', 66 | display_name: 'stridertester/privproject1', 67 | display_url: 'http://nodev/stridertester/privproject1', 68 | public: false, 69 | prefetch_config: true, 70 | creator: "55d2ecb5edb0d634165eac37", 71 | provider: { 72 | id: 'gitlab', 73 | account: '0', 74 | repo_id: '5', 75 | config: { 76 | auth: {type: 'ssh'}, 77 | scm: 'git', 78 | url: 'git@nodev:stridertester/privproject1.git', 79 | owner: { 80 | name: 'Strider Tester', 81 | username: 'stridertester', 82 | id: 3, 83 | state: 'active', 84 | avatar_url: 'http://www.gravatar.com/avatar/3f671ed86ed3d21ed3640c7a016b0997?s=40&d=identicon' 85 | }, 86 | repo: 'http://nodev/stridertester/privproject1', 87 | pull_requests: 'none', 88 | whitelist: [] 89 | } 90 | }, 91 | branches: [{ 92 | name: 'master', 93 | active: true, 94 | mirror_master: false, 95 | deploy_on_green: true, 96 | pubkey: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1j1c3wNyUwFzIhU5ELZb6tH1K+TkQgV0CrYjRvWmeZZr5aNKehSo5ntCoPtjZOddD2qYOUNyqe0EkdsSa7JeuD0blk5T9V8EADxqSmfYE8qD3Ch1JN0T4gbxoH20N45gqfpzug04FNwaDvCoxJgKvJXNj141SRLVVsa3DlByqC1Il+6TS7LqsQQMnSahgdx6fOUSLzSRG5NmbHGnS4CA1W4zyqQKzznh/Qj9WLxQKxugly3PPWtlcCDoaFBBQSOIgGVs00Bd3X8DJW/3gNPfydtUAdm/BcDZHOLyBUNOQCjR/fGyLS8D4ufYt6vr72No9O0dyKyI+FpOb+jPDG631 stridertester/privproject1-stridertester@gmail.com\n', 97 | privkey: '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAtY9XN8DclMBcyIVORC2W+rR9Svk5EIFdAq2I0b1pnmWa+WjS\nnoUqOZ7QqD7Y2TnXQ9qmDlDcqntBJHbEmuyXrg9G5ZOU/VfBAA8akpn2BPKg9wod\nSTdE+IG8aB9tDeOYKn6c7oNOBTcGg7wqMSYCryVzY9eNUkS1VbGtw5QcqgtSJfuk\n0uy6rEEDJ0moYHcenzlEi80kRuTZmxxp0uAgNVuM8qkCs854f0I/Vi8UCsboJctz\nz1rZXAg6GhQQUEjiIBlbNNAXd1/AyVv94DT38nbVAHZvwXA2Rzi8gVDTkAo0f3xs\ni0vA+Ln2Ler6+9jaPTtHcisiPhaTm/ozwxut9QIDAQABAoIBAGbtMPOheSs29iKT\nN/B8q+fKpHD5YnlR7QmUmUjWCWdLkJSt8SD+uxZZS07l+gcDvF5yOMtK2h4nq6Fh\nV0nAsKhzbqy9gqwwsHA5H8ZWU9swNUJ3UGzuUUJUQhwBHNDP4rbMemjYtUVNkXrj\nFEQymTjzkTvbufkWjHpdNPX4JFvdBGKJID9Orfq53TV/tKWQ4cuk9y6L3WcHojPo\nTx6iKc7n6GEH3OYaUeuF0LfbZGGrSO04EB0gsq/kjtjPzmTH5kVG8haVZBhbjETW\nrFQPTWfshSx6za3ecMGfvlC7Jb5JBZ7BknTHHytAGuPK0W08K9yBfkrTmhMUiEyD\nMDO7oU0CgYEA4ofELHIt7/V/YKFyCU4v7DkrCJdOcTnLHpOlMm2e3NZInGZdDp8+\n6XFKRKlk/Vv7NZg5m/liPhBRGZalWTT5x20VyTNxVN0WudjPTGbl/Q6l9nG1cu5V\nNtxX5G3o8eOcSQaiTY8IVEN96ApuYhnh2u+463WSaWc5U53Oh+0V4kcCgYEAzS3n\n9o1qmkc+KLmjYI19M5gN3sW1ZyIYa3f0i9FCqnAaKKoBrNVjSaQ5Hp/jyAc1hDtq\nS/HwztUDJNvVB5/IRacpMklrh8ReF/2kTHgM1ChCTkdsoIQOw04Sp8VJLK4ECswn\n7R+17Ff4hW0nffYfQeMeXCZd99HrbYgH564PL+MCgYBzNLzuJbt7GA2J5VGLrfnt\nVz2thtXb+5pzmH8hYGK0yT3wXJbjAtYJ/xXYSZYUzBy8KwjRbEksazvzmYvKDIkj\nhTTZOJJgqHgQWFVE8+fvhO2eokG3i8JGvlTs1YDs0+b9tKQCccW4pQJ5aiStO6CD\nqfsPtKGbfWXIQq9wrYC9rQKBgGUx5f0pJFGxH4wwes7NGdoPfY/JDT4vh8HBaQBo\nliu/nHc/2hGnMRAKCg37p/lo7NEqCLQqQK2SS7mrHrdi7ADGgEAIDBvrEslcVONO\nNm2Q6Zr4CTBl0W4sHHFYkU2TCfVVWb/O6wgFH1KXUmoCsMnrPXcPiTsH8siT1epD\nY8QnAoGAYhPbK1k6sH8bTdU6hI3TtaSZ1MOMDO2eeB0u2dpQSOiQ5a33vLM9AN2s\nHQfwA6yNn9oPf3BnJBOGxpX6W/L3ntYOVp4T/18LCZOX8f9GFwUrAAtbH52YgP/3\njveYyVbjAOkSohdCd2UhiJWoQVHcGGHrkX/bKFfyVYUlKrKpVag=\n-----END RSA PRIVATE KEY-----\n', 98 | plugins: [ 99 | { 100 | id: 'node', 101 | enabled: true, 102 | config: { 103 | fork: 'Node.js', 104 | runtime: 'whatever', 105 | caching: 'none', 106 | test: 'npm test', 107 | globals: [] 108 | } 109 | }], 110 | runner: { 111 | id: 'simple-runner', 112 | config: {pty: false} 113 | } 114 | }, 115 | {name: '*', mirror_master: true} 116 | ] 117 | }; 118 | 119 | const projectWithInvalidRepoID = deepClone(repoProject); 120 | projectWithInvalidRepoID.provider.repo_id = "invalidrepo"; 121 | 122 | const projectWithInvalidSSHKey = deepClone(repoProject); 123 | projectWithInvalidSSHKey.branches[0].pubkey = "invalid key"; 124 | 125 | const projectWithInvalidName = deepClone(repoProject); 126 | projectWithInvalidName.name = "nonexistentproject"; 127 | 128 | describe('gitlab webapp', function() { 129 | //-------------------------------------------------------------------------------------- 130 | //Test getting a json file 131 | describe('getFile', function() { 132 | before('Setup the mock gitlab server', function setupNock() { 133 | nock.cleanAll(); 134 | require('./mocks/gitlab_webapp_getfile.js')(); 135 | }); 136 | 137 | after('Tear down mock Gitlab server', function tearDownNock() { 138 | nock.cleanAll(); 139 | }); 140 | 141 | const filename = "strider.json"; 142 | 143 | const ref = { 144 | branch: 'master', 145 | }; 146 | 147 | //getFile only uses account.config 148 | const account = { 149 | api_key: 'zRtVsmeznn7ySatTrnrp', 150 | api_url: 'http://localhost:80/api/v3' 151 | }; 152 | 153 | 154 | //getFile only uses project.provider.repo_id 155 | const project = { 156 | provider: { 157 | repo_id: '5' 158 | } 159 | }; 160 | 161 | //project with strider.json missing 162 | const projectWithMissingStriderJson = { 163 | provider: { 164 | repo_id: '8' 165 | } 166 | }; 167 | 168 | 169 | it('should get a json file correctly', function(done) { 170 | webapp.getFile(filename, ref, account, providerConfig, project, function(err, text) { 171 | expect(text).to.be.a('string'); 172 | done(); 173 | }); 174 | }); 175 | 176 | //created a project priproject2 of type node.js, but not having a strider.json for this test 177 | it('should not crash, but return an error if the file could not be found', function(done) { 178 | webapp.getFile(filename, ref, account, providerConfigForProjectWithMissingStriderJson, projectWithMissingStriderJson, function(err, text) { 179 | expect(err).to.be.ok(); 180 | expect(text).to.not.be.ok(); 181 | done(); 182 | }); 183 | }); 184 | }); 185 | 186 | //-------------------------------------------------------------------------------------- 187 | //Test getting branches from a repository 188 | describe('getBranches', function() { 189 | //takes parameters - account, config, project 190 | 191 | /* 192 | NOTE: the account argument in this function is DIFFERENT from 193 | the account argument passed in to webapp.getFile. Here we get passed what is 194 | known elsewhere (in the api tests) to be a config object (i.e. one with 195 | two properties - api_url and api_key. Also note that in the webapp file, config 196 | is used to refer to an object of type project.provider.config 197 | */ 198 | const account = { 199 | api_url: 'http://localhost:80/api/v3', 200 | api_key: 'zRtVsmeznn7ySatTrnrp' 201 | }; 202 | 203 | 204 | const invalidAccount = { 205 | api_url: 'http://localhost:80/api/v3', 206 | api_key: 'badkey' 207 | }; 208 | 209 | //getBranches only uses project.provider.repo_id 210 | const project = { 211 | provider: { 212 | repo_id: '5', 213 | } 214 | }; 215 | 216 | const invalidProject = { 217 | provider: { 218 | repo_id: 'invalidrepo', 219 | } 220 | }; 221 | 222 | before('Setup the mock gitlab server', function setupNock() { 223 | nock.cleanAll(); 224 | require('./mocks/gitlab_webapp_getbranches.js')(); 225 | }); 226 | 227 | after('Tear down mock Gitlab server', function tearDownNock() { 228 | nock.cleanAll(); 229 | }); 230 | 231 | it('should get a correct list of branches in the project', function(done) { 232 | webapp.getBranches(account, providerConfig, project, function(err, branches) { 233 | //debug("Branches we get are: " + Object.prototype.toString.call(branches) + "Inspected: " + util.inspect(branches, false, null, true)); 234 | expect(branches).to.be.an('array'); 235 | expect(branches).to.eql(['firstbranch', 'master']); 236 | done(); 237 | }); 238 | }); 239 | 240 | it('should complain suitably if account data is empty', function(done) { 241 | webapp.getBranches({}, providerConfig, project, function(err, branches) { 242 | //debug("Branches we get are: " + Object.prototype.toString.call(branches) + "Inspected: " + util.inspect(branches, false, null, true)); 243 | //debug("We get ERR as: " + util.inspect(err, false, null, true)); 244 | expect(err).to.be.ok(); 245 | done(); 246 | }); 247 | }); 248 | 249 | it('should complain suitably if account data is invalid', function(done) { 250 | webapp.getBranches(invalidAccount, providerConfig, project, function(err, branches) { 251 | //debug("We get ERR as: " + err); 252 | expect(err).to.be.ok(); 253 | done(); 254 | }); 255 | }); 256 | 257 | it('should complain suitably if project.provider.repo_id is invalid', function(done) { 258 | webapp.getBranches(account, providerConfig, invalidProject, function(err, branches) { 259 | //debug("We get ERR as: " + util.inspect(err, false, null, true)); 260 | expect(err).to.be.ok(); 261 | done(); 262 | }); 263 | }); 264 | }); 265 | 266 | //-------------------------------------------------------------------------------------- 267 | describe('listRepos', function() { 268 | //takes parameters - config, callback 269 | 270 | //NOTE: what listRepos expects as config, is called account elsewhere in webapp.js 271 | const config = { 272 | api_url: 'http://localhost:80/api/v3', 273 | api_key: 'zRtVsmeznn7ySatTrnrp' 274 | }; 275 | 276 | 277 | before('Setup the mock gitlab server', function setupNock() { 278 | nock.cleanAll(); 279 | require('./mocks/gitlab_webapp_listrepos.js')(); 280 | }); 281 | 282 | after('Tear down mock Gitlab server', function tearDownNock() { 283 | nock.cleanAll(); 284 | }); 285 | 286 | it('should get a list of repositories accessible to the user correctly', function(done) { 287 | webapp.listRepos(config, function(err, repos) { 288 | expect(err).to.not.be.ok(); 289 | expect(repos).to.be.an('array'); 290 | expect(repos.length).to.eql(3); 291 | done(); 292 | }); 293 | }); 294 | 295 | it('should complain if an invalid config is passed - invalid api_url', function(done) { 296 | webapp.listRepos({api_url: 'invalidurl', api_key: 'zRtVsmeznn7ySatTrnrp'}, function(err, repos) { 297 | expect(err).to.be.ok(); 298 | done(); 299 | }); 300 | }); 301 | 302 | it('should complain if invalid credentials are passed - wrong api_key', function(done) { 303 | webapp.listRepos(wrongCredentialsConfig, function(err, repos) { 304 | expect(err).to.be.ok(); 305 | done(); 306 | }); 307 | }); 308 | }); 309 | 310 | //-------------------------------------------------------------------------------------- 311 | describe('setupRepo', function() { 312 | //takes parameters - account, project, config, callback 313 | const account = { 314 | api_url: 'http://localhost:80/api/v3', 315 | api_key: 'zRtVsmeznn7ySatTrnrp' 316 | }; 317 | 318 | before('Setup the mock gitlab server', function setupNock() { 319 | nock.cleanAll(); 320 | require('./mocks/gitlab_webapp_setuprepo.js')(); 321 | }); 322 | 323 | after('Tear down mock Gitlab server', function tearDownNock() { 324 | nock.cleanAll(); 325 | }); 326 | 327 | it('should callback with the same config object that we passed in as the second parameter if repo was set up successfully', function(done) { 328 | webapp.setupRepo(account, providerConfig, repoProject, function(err, receivedConf) { 329 | expect(err).to.not.be.ok(); 330 | expect(receivedConf).to.eql(providerConfig); 331 | done(); 332 | }); 333 | }); 334 | 335 | it('should callback with an error if invalid credentials are supplied', function(done) { 336 | webapp.setupRepo(wrongCredentialsConfig, providerConfig, repoProject, function(err, receivedConf) { 337 | expect(err).to.be.ok(); 338 | done(); 339 | }); 340 | }); 341 | 342 | it('should callback with an error if project.provider.repo_id is invalid', function(done) { 343 | webapp.setupRepo(account, providerConfig, projectWithInvalidRepoID, function(err, receivedConf) { 344 | expect(err).to.be.ok(); 345 | done(); 346 | }); 347 | }); 348 | 349 | it('should callback with an error if project.branches[0].pubkey is not a valid ssh public key', function(done) { 350 | webapp.setupRepo(account, providerConfig, projectWithInvalidSSHKey, function(err, receivedConf) { 351 | expect(err).to.be.ok(); 352 | done(); 353 | }); 354 | }); 355 | }); 356 | 357 | //-------------------------------------------------------------------------------------- 358 | describe('tearDownRepo', function() { 359 | //takes parameters - account, project, config, callback 360 | const account = { 361 | api_url: 'http://localhost:80/api/v3', 362 | api_key: 'zRtVsmeznn7ySatTrnrp' 363 | }; 364 | 365 | before('Setup the mock gitlab server', function setupNock() { 366 | nock.cleanAll(); 367 | require('./mocks/gitlab_webapp_teardownrepos.js')(); 368 | }); 369 | 370 | after('Tear down mock Gitlab server', function tearDownNock() { 371 | nock.cleanAll(); 372 | }); 373 | 374 | it('should callback on success with no parameters if the repo was destroyed successfully', function(done) { 375 | webapp.teardownRepo(account, providerConfig, repoProject, function(err) { 376 | expect(err).to.not.be.ok(); 377 | done(); 378 | }); 379 | }); 380 | 381 | it('should callback with an error if invalid credentials are supplied', function(done) { 382 | webapp.teardownRepo(wrongCredentialsConfig, providerConfig, repoProject, function(err) { 383 | expect(err).to.be.ok(); 384 | done(); 385 | }); 386 | }); 387 | 388 | it('should callback with an error if project.provider.repo_id is invalid', function(done) { 389 | webapp.teardownRepo(account, providerConfig, projectWithInvalidRepoID, function(err) { 390 | expect(err).to.be.ok(); 391 | done(); 392 | }); 393 | }); 394 | 395 | it.skip('should callback with an error if an invalid project name is given', function(done) { 396 | webapp.teardownRepo(account, providerConfig, projectWithInvalidName, function(err) { 397 | //TODO: what happens here is that the title does not match that of the key and 398 | //the key is not deleted. In that case, we are silently ignoring the was_deleted flag 399 | //and directly calling done with a null error 400 | expect(err).to.be.ok(); 401 | done(); 402 | }); 403 | }); 404 | }); 405 | }); 406 | -------------------------------------------------------------------------------- /test/test_webhooks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Used to test the gitlab webhooks 5 | */ 6 | 7 | const expect = require('expect.js'); 8 | const webhooks = require('../lib/webhooks'); 9 | let util = require('util'); 10 | let debug = require('debug')('strider-gitlab:test:webhooks'); 11 | 12 | describe('receiving webhooks from the gitlab server', function() { 13 | //-------------------------------------------------------------------------------------- 14 | describe('receiveWebhook', function() { 15 | //It takes three parameters, emitter, req and res 16 | 17 | it('should emit a job.prepare event on emitter AND return a 204 response if the payload was parsed successfully and a job could be created', function(done) { 18 | let expected_successes_remaining = 2; 19 | 20 | //the test should pass only when mockRes.sendStatus gets called with 204 AND when 21 | //emitter receives this signal with the jobObject, doing assertion counting to 22 | //ensure both conditions are successful. TODO: Is there a better way to do this with Mocha? 23 | 24 | function checkDone() { 25 | expected_successes_remaining--; 26 | if(expected_successes_remaining === 0) { 27 | done(); 28 | } 29 | } 30 | 31 | //This will get the job.prepare event when the job is successfully created 32 | const emitter = new (require('events').EventEmitter); 33 | 34 | //This contains the payload received from the gitlab server in 35 | //body and project information from strider 36 | const mockReq = require('./mocks/receive_webhooks_req.js'); 37 | 38 | //On receiving the payload we are expected to send a 204 immediately (?) 39 | //perhaps we should send a 400 if we could not parse the payload 40 | const mockRes = { 41 | sendStatus: function(code) { 42 | expect(code).to.eql(204); 43 | checkDone(); 44 | } 45 | }; 46 | 47 | emitter.on('job.prepare', function(jobObject) { 48 | expect(jobObject.type).to.eql("TEST_AND_DEPLOY"); 49 | expect(jobObject.trigger.type).to.eql("commit"); 50 | expect(jobObject.ref.branch).to.eql("master"); 51 | expect(jobObject.ref.id).to.eql("6a00c57e69bd4e269496ca27973191ecafcf8b20"); 52 | checkDone(); 53 | }); 54 | 55 | webhooks.receiveWebhook(emitter, mockReq, mockRes); 56 | 57 | }); 58 | 59 | it('should send a 400 error in the res if the payload cannot be parsed'); 60 | 61 | }); 62 | 63 | //-------------------------------------------------------------------------------------- 64 | describe('pushJob', function() { 65 | //pushJob takes one parameter - a payload object 66 | 67 | it('should be able to parse the payload and return an object with branch, trigger, deploy and ref', function() { 68 | const samplePayload = require('./mocks/sample_payload.js'); 69 | const config = webhooks.pushJob(samplePayload); 70 | expect(config).to.eql({ 71 | branch: 'master', 72 | trigger: { 73 | type: 'commit', 74 | author: { 75 | name: 'Strider Tester', 76 | username: undefined, 77 | email: 'stridertester@gmail.com', 78 | image: 'https://s.gravatar.com/avatar/3f671ed86ed3d21ed3640c7a016b0997' 79 | }, 80 | url: 'http://nodev/stridertester/privproject1/commit/352e6fe2ea42d394a21dc7995df2116e86bb0684', 81 | message: 'updated strider.json\n', 82 | timestamp: '2015-08-26T20:02:07+09:00', 83 | source: {type: 'plugin', plugin: 'gitlab'} 84 | }, 85 | deploy: true, 86 | ref: { 87 | branch: 'master', 88 | id: '352e6fe2ea42d394a21dc7995df2116e86bb0684' 89 | } 90 | }); 91 | }); 92 | }); 93 | 94 | 95 | //-------------------------------------------------------------------------------------- 96 | describe('pushJob', function() { 97 | //pushJob takes one parameter - a payload object 98 | 99 | it('should be able to parse the payload and return an object with branch, trigger, deploy and ref by gitlab v7', function() { 100 | const samplePayload = require('./mocks/sample_payload_tag_push_with_v7.x.js'); 101 | const config = webhooks.pushJob(samplePayload); 102 | expect(config).to.eql({ 103 | branch: 'tag-1.1.2', 104 | trigger: { 105 | type: 'tag push', 106 | author: { 107 | name: 'Strider Tester', 108 | username: undefined, 109 | email: undefined, 110 | image: 'https://s.gravatar.com/avatar/d415f0e30c471dfdd9bc4f827329ef48' 111 | }, 112 | url: 'http://nodev/stridertester/privproject1/commit/352e6fe2ea42d394a21dc7995df2116e86bb0684', 113 | message: 'tag push', 114 | timestamp: config.trigger.timestamp, 115 | source: { type: 'plugin', plugin: 'gitlab' } 116 | }, 117 | deploy: true, 118 | ref: { 119 | branch: 'tag-1.1.2', 120 | id: '352e6fe2ea42d394a21dc7995df2116e86bb0684' 121 | } 122 | }); 123 | }); 124 | }); 125 | 126 | }); 127 | -------------------------------------------------------------------------------- /test/test_worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Used to test the gitlab worker 5 | */ 6 | 7 | const proxyquire = require('proxyquire'); 8 | const expect = require('expect.js'); 9 | let util = require('util'); 10 | let debug = require('debug')('strider-gitlab:test:webapp'); 11 | 12 | const gitStub = {}; 13 | 14 | gitStub.fetch = function(dest, config, job, context, done) { 15 | done(); 16 | }; 17 | 18 | const worker = proxyquire('../lib/worker', {'strider-git/worker': gitStub}); 19 | 20 | describe('gitlab worker', function() { 21 | //-------------------------------------------------------------------------------------- 22 | describe('init', function() { 23 | const dirs = { 24 | base: '/home/dev/.strider', 25 | data: '/home/dev/.strider/data/stridertester-privproject1-55de9a6c1cfc0d872d309dbb', 26 | cache: '/home/dev/.strider/cache/stridertester/privproject1' 27 | }; 28 | 29 | const account = { 30 | api_url: 'http://localhost:80/api/v3', 31 | api_key: 'zRtVsmeznn7ySatTrnrp' 32 | }; 33 | 34 | const config = { 35 | whitelist: [], 36 | pull_requests: 'none', 37 | repo: 'http://nodev/stridertester/privproject1', 38 | owner: { 39 | avatar_url: 'http://www.gravatar.com/avatar/3f671ed86ed3d21ed3640c7a016b0997?s=40&d=identicon', 40 | state: 'active', 41 | id: 3, 42 | username: 'stridertester', 43 | name: 'Strider Tester' 44 | }, 45 | url: 'git@nodev:stridertester/privproject1.git', 46 | scm: 'git', 47 | auth: {type: 'ssh'} 48 | }; 49 | 50 | const job = {}; 51 | 52 | it('should call back with err as null and the second param as an object with three properties, config, account and a fetch function', function(done) { 53 | worker.init(dirs, account, config, job, function(err, object) { 54 | expect(err).to.not.be.ok(); 55 | expect(object.config).to.eql(config); 56 | expect(object.account).to.eql(account); 57 | expect(object.fetch).to.be.a('function'); 58 | done(); 59 | }); 60 | }); 61 | 62 | it('should check for invalid arguments and operational errors ?'); 63 | }); 64 | 65 | //-------------------------------------------------------------------------------------- 66 | describe('fetch', function() { 67 | 68 | it('should call our callback after strider-git/worker fetch is done with its task', function(done) { 69 | const dest = ""; 70 | const account = { 71 | accessToken: "abcd" 72 | }; 73 | const config = { 74 | auth: { 75 | type: "https", 76 | username: "strider" 77 | } 78 | }; 79 | const job = {}; 80 | const context = {}; 81 | 82 | worker.fetch(dest, account, config, job, context, done); 83 | }); 84 | 85 | it('should check for invalid arguments and operational errors ?'); 86 | }); 87 | 88 | }); 89 | --------------------------------------------------------------------------------