-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Digger minimal node client backbone #1
Changes from 5 commits
aadf748
871db65
52b132d
31eba05
00dd80d
90c4d80
a42a087
8d52967
c834be8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules | ||
jspm_packages | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
// Use IntelliSense to learn about possible Node.js debug attributes. | ||
// Hover to view descriptions of existing attributes. | ||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"type": "node", | ||
"request": "launch", | ||
"name": "Launch Program", | ||
"program": "${workspaceRoot}/bin/digkins.js", | ||
"cwd": "${workspaceRoot}", | ||
"outFiles": [], | ||
// Replace args with any command you wish for debugging | ||
//"args":["job","create","test"], | ||
"sourceMaps": true | ||
}, | ||
{ | ||
"type": "node", | ||
"request": "attach", | ||
"name": "Attach to Process", | ||
"port": 5858, | ||
"outFiles": [], | ||
"sourceMaps": true | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
## AeroGear Digger Node.js client | ||
|
||
AeroGear digger node.js command line client. | ||
Create Jenkins job and build your application using Jenkinsfile located in your source code. | ||
For more information about this project go to https://github.com/aerogear/digger-jenkins | ||
|
||
## Sample use case | ||
|
||
Login to Jenkins. Your credentials will be stored in configuration. | ||
``` | ||
digkins login http://myjenkins.com | ||
``` | ||
|
||
Create job that would use your repository as source code | ||
``` | ||
digkins job create my-androip-build https://github.com/android-build/project master | ||
``` | ||
|
||
Trigger build | ||
``` | ||
digkins job build my-androip-build | ||
``` | ||
|
||
## Supported commands | ||
``` | ||
Trigger build for Jenkins job | ||
digkins job build <jobname> | ||
|
||
Create jenkins job for git repository with Jenkinsfile | ||
digkins job create <name> [repository] [branch] | ||
|
||
Setup jenkins credetials and login into jenkins | ||
digkins login <url> [user] [password] | ||
|
||
Stream jenkins logs for triggered build | ||
digkins log <job> <queueid> | ||
|
||
Generate bash completion script | ||
digkins completion | ||
``` | ||
## Development | ||
|
||
1. Install node.js | ||
2. Checkout repository | ||
3. Link library to use directly from source code | ||
|
||
`npm link .` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env node | ||
|
||
var yargonaut = require('yargonaut') | ||
.style('red') | ||
.helpStyle('green') | ||
.errorsStyle('red') | ||
var yargs = require('yargs'); | ||
|
||
yargs.commandDir("../lib/commands") | ||
.help('help') | ||
.alias('h', 'help') | ||
.strict(true) | ||
.demand(1) | ||
.version() | ||
.completion() | ||
.argv |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
var fs = require("fs"); | ||
var path = require('path'); | ||
var _ = require('underscore'); | ||
var authHelper = require("../util/auth") | ||
|
||
/** | ||
* Create jenkins job | ||
*/ | ||
module.exports = (auth, jobArgs, callback) => { | ||
var options = authHelper.createJenkinsOptions(auth.url, auth.user, auth.password); | ||
var jenkins = require('jenkins')(options); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO I would avoid using |
||
var fileLocation = path.join(__dirname, '..', '..', 'templates', 'standard.xml'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need a Jenkins XML / template file here ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's just plain template to create job. We using jenkinsfiles but we would need some simple xml file to create job that would have only giturl and branch configured. Rest would come from Jenkinsfile itself. I investigated Jenkinfile's automatic job creation and it's really powerful, but for our internal needs we would need to create job explicitly. |
||
var fileContent = fs.readFileSync(fileLocation, 'utf8'); | ||
if (fileContent) { | ||
var jobTemplate = _.template(fileContent); | ||
jobXML = jobTemplate(jobArgs); | ||
var options = { | ||
name: jobArgs.name, | ||
xml: jobXML | ||
} | ||
jenkins.job.create(options, function (err, data) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest using arrow function instead, for consistency |
||
callback(err, data); | ||
}); | ||
} else { | ||
callback("Standard template is missing!"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning a promise instead of using a callback would increase readability and simplicity. I strongly recommend using them from the beginning, specially when you can use node built-in promises. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @josemigallas Let's not start flame wars here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No flame wars at all, just my humble suggestion, don't get me wrong. I read already that repo and it's said nothing about the preferred use of callback/Promise. However, from the last discussion I understood that Promises are preferred. |
||
} | ||
|
||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
var authUtil = require("../util/auth") | ||
|
||
// Retrieve jenkins server information | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just an observation: the other doc is written with block format (/** ... */) but here is line format (// ...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here the doc is written in single line format (// ...) but in the other files is with block format (/** ... */) I suggest using always the block format. |
||
module.exports = (auth, callback) => { | ||
var options = authUtil.createJenkinsOptions(auth.url, auth.user, auth.password); | ||
options.crumbIssuer = true; | ||
var jenkins = require('jenkins')(options); | ||
jenkins.info(function (err, data) { | ||
callback(err, data); | ||
}); | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
var fs = require("fs"); | ||
var path = require('path'); | ||
var _ = require('underscore'); | ||
var authHelper = require("../util/auth"); | ||
|
||
/** | ||
* Stream jenkins logs | ||
*/ | ||
module.exports = (auth, jobName, queueNumber,writter, callback) => { | ||
var options = authHelper.createJenkinsOptions(auth.url, auth.user, auth.password); | ||
var jenkins = require('jenkins')(options); | ||
jenkins.queue.item(queueNumber, function (err, data) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
if (!data.executable || !data.executable.number) { | ||
return writter.log("Build did not started yet! Try again later"); | ||
} | ||
var buildNo = data.executable.number; | ||
|
||
const logStream = jenkins.build.logStream(jobName, buildNo); | ||
writter.log(`## Starting streaming build ${buildNo} log`); | ||
logStream.on('data', function (text) { | ||
writter.log(text); | ||
}); | ||
logStream.on('error', function (err) { | ||
writter.error(err); | ||
}); | ||
|
||
logStream.on('end', function () { | ||
writter.log('Build finished'.gray); | ||
callback(err, data); | ||
}); | ||
}); | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
var fs = require("fs"); | ||
var path = require('path'); | ||
var _ = require('underscore'); | ||
var authHelper = require("../util/auth"); | ||
|
||
/** | ||
* Trigger jenkins build | ||
*/ | ||
module.exports = (auth, jobName, callback) => { | ||
var options = authHelper.createJenkinsOptions(auth.url, auth.user, auth.password); | ||
var jenkins = require('jenkins')(options); | ||
jenkins.job.build(jobName, function (err, queueNumber) { | ||
callback(err, queueNumber); | ||
}); | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
exports.command = 'job <command>' | ||
exports.desc = 'Manage jenkins jobs' | ||
exports.builder = function (yargs) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, here is a clearer example that the code cleanness would benefit from using arrow functions. |
||
return yargs.commandDir('jobs') | ||
} | ||
exports.handler = function (argv) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Build jenkins job command | ||
var conf = require("../../util/config"); | ||
var logger = require("../../util/logger"); | ||
var prompt = require('readline-sync'); | ||
|
||
var triggerBuild = require("../../api/triggerBuild"); | ||
|
||
exports.command = 'build <job>' | ||
exports.describe = 'Trigger build for Jenkins job' | ||
exports.builder = (yargs) => { | ||
return yargs.count('verbose').alias('v', 'verbose'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO this would looks utterly better on a single line without There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That should be part of the javascript styling tool - something like eslint. Going to add this soon. Any manual styling are hard to enforce and I do not want to make changes for this now until we would have automatic process in place that would fail the build. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I mean is that it should be |
||
} | ||
|
||
exports.handler = (argv) => { | ||
if (!argv.job) { | ||
argv.job = prompt.question('Jenkins job name: '); | ||
} | ||
triggerBuild(conf.get("auth"), argv.job, function (err, queueNumber) { | ||
if (err) { | ||
logger.error(`Problem when triggering new build for ${argv.job} job`); | ||
if (argv.v) { | ||
logger.error(err); | ||
} | ||
return; | ||
} | ||
logger.info(`Build for job ${argv.job} started! Use "log ${argv.job} ${queueNumber}" command to fetch logs`); | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Create jenkins job command | ||
var conf = require("../../util/config"); | ||
var logger = require("../../util/logger"); | ||
var prompt = require('readline-sync'); | ||
|
||
var createJobApi = require("../../api/createJob"); | ||
|
||
exports.command = 'create <name> [repository] [branch]' | ||
exports.aliases = ["new"]; | ||
exports.describe = 'Create jenkins job for git repository with Jenkinsfile' | ||
exports.builder = (yargs) => { | ||
return yargs.count('verbose').alias('v', 'verbose'); | ||
} | ||
|
||
exports.handler = (argv) => { | ||
if (!argv.repository) { | ||
argv.user = prompt.question('Git repository to use: '); | ||
} | ||
if (!argv.branch) { | ||
argv.password = prompt.question('Git branch to checkout: '); | ||
} | ||
createJobApi(conf.get("auth"), { | ||
name: argv.name, | ||
repository: argv.repository, | ||
branch: argv.branch | ||
}, function (err, data) { | ||
if (err) { | ||
logger.error(`Problem when creating ${argv.name} job`); | ||
if (argv.verbose) { | ||
logger.error(err); | ||
} | ||
return; | ||
} | ||
logger.info(`Job ${argv.name} created!`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This indentation is one step further making it less readable. |
||
if (argv.verbose) { | ||
logger.debug(data); | ||
} | ||
}); | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Login into jenkins command | ||
var conf = require("../util/config"); | ||
var logger = require("../util/logger"); | ||
var prompt = require('readline-sync'); | ||
|
||
var infoApi = require("../api/jenkinsInfo"); | ||
|
||
exports.command = 'login <url> [user] [password]' | ||
exports.aliases = ["setup", "init"]; | ||
exports.describe = 'Setup jenkins credetials and login into jenkins' | ||
exports.builder = (yargs) => { | ||
return yargs.count('verbose').alias('v', 'verbose'); | ||
} | ||
exports.handler = (argv) => { | ||
if (!argv.user) { | ||
argv.user = prompt.question('Username: '); | ||
} | ||
if (!argv.password) { | ||
argv.password = prompt.question('Password: ',{ hideEchoBack: true}); | ||
} | ||
var auth = { | ||
url: argv.url, | ||
user: argv.user, | ||
password: argv.password | ||
} | ||
infoApi(auth, function (err, data) { | ||
if(err){ | ||
logger.info("Cannot connect to jenkins instance", err); | ||
return; | ||
} | ||
if (data) { | ||
logger.info("Login succesfull! Connected to jenkins!"); | ||
conf.set("auth", auth); | ||
if (argv.verbose) { | ||
logger.debug(JSON.stringify(data, null, 4)); | ||
} | ||
} | ||
}); | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
credetials -> credentials