From 3c8aafcbc2d1f3088e17ef8d875c49786be44a6c Mon Sep 17 00:00:00 2001 From: "didier.amyot" Date: Mon, 20 Jan 2014 08:26:45 -0500 Subject: [PATCH] Started from strider-git --- .gitignore | 3 + .jshintrc | 14 ++++ Makefile | 10 +++ Readme.md | 14 ++++ config/config.html | 49 +++++++++++ get_branches.py | 6 ++ lib/get_branches.py | 6 ++ lib/index.js | 120 +++++++++++++++++++++++++++ package.json | 41 +++++++++ strider-hg.komodoproject | 4 + webapp.js | 57 +++++++++++++ worker.js | 174 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 498 insertions(+) create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 config/config.html create mode 100644 get_branches.py create mode 100644 lib/get_branches.py create mode 100644 lib/index.js create mode 100644 package.json create mode 100644 strider-hg.komodoproject create mode 100644 webapp.js create mode 100644 worker.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8953fa0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +*~ +*# \ No newline at end of file diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..fc49338 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,14 @@ +{ + "strict": false, + "laxcomma": true, + "undef": true, + "node": true, + "-W033": false, + "-W024": false, + "-W030": false, + "-W069": false, + "-W089": false, + "-W098": false, + "-W116": false, + "-W065": false +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..97b9133 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ + +test: lint + @./node_modules/.bin/mocha -R spec + +tolint := *.js *.json lib + +lint: + @./node_modules/.bin/jshint --verbose $(tolint) + +.PHONY: test lint watch build less diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4d5d566 --- /dev/null +++ b/Readme.md @@ -0,0 +1,14 @@ +## Git provider + +Allow strider to use any git repository for a project. + +### Config + +- url +- display_url (optional) +- auth + - ssh + - custom priv/pubkey if you want + - https + - username + - password diff --git a/config/config.html b/config/config.html new file mode 100644 index 0000000..84553c6 --- /dev/null +++ b/config/config.html @@ -0,0 +1,49 @@ + +
+

Auth type

+
+
SSH
+
HTTP
+
HTTPS
+
+
+

Ssh Keys

+ + Leave these blank to use the project's private and public keys + (you can find those under the "General" tab). + +
+
+ + +
+
+ + +
+
+
+
+ Http(s) auth + + +
+
+ diff --git a/get_branches.py b/get_branches.py new file mode 100644 index 0000000..34521fd --- /dev/null +++ b/get_branches.py @@ -0,0 +1,6 @@ +from mercurial import ui, hg, node +from sys import argv + +peer = hg.peer(ui.ui(), {}, argv[1]) +for name, rev in peer.branchmap().items(): + print(name) \ No newline at end of file diff --git a/lib/get_branches.py b/lib/get_branches.py new file mode 100644 index 0000000..34521fd --- /dev/null +++ b/lib/get_branches.py @@ -0,0 +1,6 @@ +from mercurial import ui, hg, node +from sys import argv + +peer = hg.peer(ui.ui(), {}, argv[1]) +for name, rev in peer.branchmap().items(): + print(name) \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..485e70a --- /dev/null +++ b/lib/index.js @@ -0,0 +1,120 @@ + +var gitane = require('gitane') + , exec = require('child_process').exec + , shellescape = require('shell-escape') + , path = require('path') + , _ = require('underscore') + +module.exports = { + gitUrl: gitUrl, + sshUrl: sshUrl, + httpUrl: httpUrl, + gitCmd: gitCmd, + gitaneCmd: gitaneCmd, + processBranches: processBranches, + getBranches: getBranches, + shellEscape: shellEscape +} + +function shellEscape(one) { + if (!one) { + throw new Error('trying to escape nothing', one) + } + return shellescape([one]) +} + +// returns [real, safe] urls +function gitUrl(config) { + return (config.auth.type === 'ssh' ? sshUrl : httpUrl)(config) +} + +function sshUrl(config) { + var base = config.url.split('//')[1] + , url = shellEscape('git@' + base.replace('/', ':')) + return [url, url] +} + +function httpUrl(config) { + var base = config.url.split('//')[1] + , url = config.auth.type + '://' + config.auth.username + ':' + config.auth.password + '@' + base + , safe = config.auth.type + '://[username]:[password]@' + base + return [url, safe] +} + +function gitCmd(cmd, cwd, auth, context, done) { + if (auth.type === 'ssh') { + return gitaneCmd(cmd, cwd, auth.privkey, context, done) + } + context.cmd({ + cmd: cmd, + cwd: cwd + }, done) +} + + + +// run a strider command with gitane +function gitaneCmd(cmd, dest, privkey, context, done) { + var start = new Date() + context.status('command.start', { command: cmd, time: start, plugin: context.plugin }) + gitane.run({ + emitter: { + emit: context.status + }, + cmd: cmd, + baseDir: dest, + privKey: privkey, + detached: true + }, function (err, stdout, stderr, exitCode) { + var end = new Date() + , elapsed = end.getTime() - start.getTime() + if (err) { + context.log('Gitane error:', err.message) + } + context.log('gitane command done %s; exit code %s; duration %s', cmd, exitCode, elapsed) + context.status('command.done', {exitCode: exitCode, time: end, elapsed: elapsed}) + done(err ? 500 : exitCode, stdout + stderr) + }) +} + +function processBranches(data, done) { + done(null, data.trim().split(/\n+/).map(function (line) { + return line.split(/\s+/)[1].split('/').slice(-1)[0] + })) +} + + + +function getBranches(config, privkey, done) { + if (config.auth.type === 'ssh') { + gitane.run({ + cmd: 'git ls-remote -h ' + gitUrl(config)[0], + baseDir: '/', + privKey: config.auth.privkey || privkey, + detached: true + }, function (err, stdout, stderr, exitCode) { + if (err || exitCode !== 0) return done(err || new Error(stderr)) + processBranches(stdout, done) + }) + } else { + exec('git ls-remote -h ' + httpUrl(config)[0], function (err, stdout, stderr) { + if (err) return done(err) + processBranches(stdout, done) + }) + } +} + +function getMercurialBranches(repoLocation){ + var pythonScript = path.join(__dirname, 'get_branches.py'); + var cmd = 'python ' + pythonScript + " " + repoLocation; + exec(cmd, function (err, stdout, stderr) { + if (err){ + return console.log(err) + }else{ + return console.log(_.filter(stdout.split("\n"),function(v){return !!v} )) + } + }) +} +getMercurialBranches('ssh://hg@bitbucket.org/ustraca/crypto') +console.log("ok?") + diff --git a/package.json b/package.json new file mode 100644 index 0000000..d02124b --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "strider-git", + "version": "0.1.0", + "description": "Strider provider for git repositories", + "main": "worker.js", + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "https://github.com/Strider-CD/strider-git" + }, + "keywords": [ + "strider", + "plugin", + "provider", + "git" + ], + "author": "Jared Forsyth ", + "license": "MIT", + "readmeFilename": "Readme.md", + "strider": { + "id": "git", + "title": "Git", + "type": "provider", + "webapp": "webapp.js", + "worker": "worker.js", + "inline_icon": "code-fork", + "config": true + }, + "dependencies": { + "gitane": "~0.3.1", + "shell-escape": "0.0.1", + "mkdirp": "~0.3.5", + "underscore": "~1.5.2" + }, + "devDependencies": { + "jshint": "~2.3.0", + "mocha": "~1.13.0" + } +} diff --git a/strider-hg.komodoproject b/strider-hg.komodoproject new file mode 100644 index 0000000..367d77c --- /dev/null +++ b/strider-hg.komodoproject @@ -0,0 +1,4 @@ + + + + diff --git a/webapp.js b/webapp.js new file mode 100644 index 0000000..1d34219 --- /dev/null +++ b/webapp.js @@ -0,0 +1,57 @@ + +var utils = require('./lib') + +function sanitizeConfig(config) { // v + if (!config.auth) return false + return { + url: config.url, + display_url: config.display_url, + auth: { + type: config.auth.type, + privkey: config.auth.privkey, + pubkey: config.auth.pubkey, + username: config.auth.username, + password: config.auth.password + } + } +} + +module.exports = { + config: { + url: String, + display_url: String, + auth: { + type: { type: String, enum: ['ssh', 'https', 'http'] }, + privkey: String, + pubkey: String, + username: String, + password: String + } + }, + getBranches: function (userConfig, config, project, done) { + utils.getBranches(config, project.privkey, done) + }, + // native git doesn't have a great way to just get a single file at an arbitrary revision + fastFile: false, + getFile: function (filename, ref, config, project, done) { + done(new Error('not implemented')); + // utils.gitcmd('git archive --remote=' + url + ' ' + (ref.fetch || ref.id) + ' .strider.json', ...); + }, + routes: function (app, context) { + app.get('config', context.auth.requireProjectAdmin, function (req, res) { + res.send(req.providerConfig()) + }) + app.put('config', context.auth.requireProjectAdmin, function (req, res) { + // validate the config + var config = sanitizeConfig(req.body) + req.providerConfig(config, function (err) { + if (err) { + res.status(500) + return res.send({errors: [err.message]}) + } + res.send({success: true, message: 'Saved git config!', config: config}) + }) + }) + } +} + diff --git a/worker.js b/worker.js new file mode 100644 index 0000000..b89acb6 --- /dev/null +++ b/worker.js @@ -0,0 +1,174 @@ + +var path = require('path') + , fs = require('fs') + , spawn = require('child_process').spawn + , mkdirp = require('mkdirp') + + , utils = require('./lib') + +function safespawn() { + var c + try { + c = spawn.apply(null, arguments) + } catch (e) { + throw new Error('Failed to start command: ' + JSON.stringify([].slice.call(arguments))) + } + c.on('error', function (err) { + // suppress node errors + }) + return c +} + +function httpCloneCmd(config, branch) { + var urls = utils.httpUrl(config) + , screen = 'git clone --recursive ' + urls[1] + ' .' + , args = ['clone', '--recursive', urls[0], '.'] + if (branch) { + args = args.concat(['-b', branch]) + screen += ' -b ' + branch + } + return { + command: 'git', + args: args, + screen: screen + } +} + +function pull(dest, config, context, done) { + context.cmd({ + cmd: 'git reset --hard', + cwd: dest + }, function (exitCode) { + utils.gitCmd('git pull', dest, config.auth, context, done) + }) +} + +function gitVersion(next) { + var child = safespawn('git', ['--version']) + , out = '' + child.stdout.setEncoding('utf8') + child.stderr.setEncoding('utf8') + child.stdout.on('data', function (data) { + out += data + }) + child.stderr.on('data', function (data) { + out += data + }) + child.on('close', function (code) { + if (code) return next(new Error('Failed to get git version: ' + out)) + next(null, out) + }) + child.on('error', function () {}) +} + + +function clone(dest, config, ref, context, done) { + if (config.auth.type === 'ssh') { + var cmd = 'git clone --recursive ' + utils.sshUrl(config)[0] + ' .' + if (ref.branch) { + cmd += ' -b ' + ref.branch + // this /only/ gets the one branch; so only use if we won't be caching + if (!config.cache) cmd += ' --single-branch' + } + return utils.gitaneCmd(cmd, dest, config.auth.privkey, context, done) + } + context.cmd({ + cmd: httpCloneCmd(config), + cwd: dest + }, done) +} + +function badCode(name, code) { + var e = new Error(name + ' failed with code ' + code) + e.code = code + e.exitCode = code + return e +} + +module.exports = { + init: function (dirs, config, job, done) { + return done(null, { + config: config, + fetch: function (context, done) { + module.exports.fetch(dirs.data, config, job, context, done) + } + }) + }, + fetch: fetch +} + +function getMasterPrivKey(branches) { + for (var i=0; i