Merge pull request #618 from mozilla/issue-530-ver-txt
feature(server): add /ver.json endpoint and route definition processing.
This commit is contained in:
Коммит
ec09cdc634
|
@ -108,7 +108,8 @@
|
|||
"0.0.7": "9088ab5ae1e861f4d81b176b4a8046080703deed"
|
||||
},
|
||||
"bluebird": {
|
||||
"1.0.5": "ef7d5f01bb741938a7cac5b4fb6cfc0622759b9e"
|
||||
"1.0.5": "ef7d5f01bb741938a7cac5b4fb6cfc0622759b9e",
|
||||
"1.0.7": "55b97e965b3f9ca6f2b3cb1fd432e1830fb00ed1"
|
||||
},
|
||||
"boolbase": {
|
||||
"1.0.0": "68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"author": "Mozilla (https://mozilla.org/)",
|
||||
"license": "MPL 2.0",
|
||||
"dependencies": {
|
||||
"bluebird": "1.0.7",
|
||||
"bower": "1.2.8",
|
||||
"connect-cachify": "0.0.15",
|
||||
"connect-fonts": "0.0.12",
|
||||
|
|
|
@ -7,7 +7,45 @@
|
|||
|
||||
var url = require('url');
|
||||
var dns = require('dns');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var config = require('./configuration');
|
||||
var logger = require('intel').getLogger('server.routes');
|
||||
|
||||
/**
|
||||
* Steal a concept from Persona and load routes from definition
|
||||
* files in the `routes` subdirectory. Each definition must contain
|
||||
* 3 attributes, method, path and process.
|
||||
* method is one of `GET`, `POST`, etc.
|
||||
* path is a string or regular expression that express uses to match a route.
|
||||
* process is a function that is called with req and res to handle the route.
|
||||
*/
|
||||
function isValidRoute(route) {
|
||||
return !! route.method && route.path && route.process;
|
||||
}
|
||||
|
||||
function loadRouteDefinitions(routesPath) {
|
||||
var routes = [];
|
||||
|
||||
fs.readdirSync(routesPath).forEach(function (file) {
|
||||
// skip files that don't have a .js suffix or start with a dot
|
||||
if (path.extname(file) !== '.js' || /^\./.test(file)) {
|
||||
return logger.info('route definition not loaded: %s', file);
|
||||
}
|
||||
|
||||
var route = require(path.join(routesPath, file));
|
||||
if (! isValidRoute(route)) {
|
||||
return logger.error('route definition invalid: %s', file);
|
||||
}
|
||||
|
||||
routes.push(route);
|
||||
});
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
var routesPath = path.join(__dirname, 'routes');
|
||||
var routes = loadRouteDefinitions(routesPath);
|
||||
|
||||
module.exports = function (fxAccountUrl, templates) {
|
||||
|
||||
|
@ -57,7 +95,7 @@ module.exports = function (fxAccountUrl, templates) {
|
|||
if (config.get('env') === 'development') {
|
||||
app.get('/tests/index.html', function (req, res) {
|
||||
var checkCoverage = 'coverage' in req.query &&
|
||||
req.query['coverage'] !== 'false';
|
||||
req.query.coverage !== 'false';
|
||||
return res.render('mocha', {
|
||||
check_coverage: checkCoverage
|
||||
});
|
||||
|
@ -95,10 +133,14 @@ module.exports = function (fxAccountUrl, templates) {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
app.get('/', function(req, res) {
|
||||
res.render('index');
|
||||
});
|
||||
|
||||
routes.forEach(function (route) {
|
||||
app[route.method](route.path, route.process);
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Return version info based on package.json and the git hash
|
||||
*
|
||||
* We figure out the Git hash in the following order:
|
||||
*
|
||||
* (1) read config/version.json if exists (ie. staging, production)
|
||||
* (2) figure it out from git (either regular '.git', or
|
||||
* '/home/app/git' for AwsBox)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var child_process = require('child_process');
|
||||
var Promise = require('bluebird');
|
||||
var logger = require('intel').getLogger('server.ver.json');
|
||||
|
||||
var version = require('../../../package.json').version;
|
||||
|
||||
exports.method = 'get';
|
||||
exports.path = '/ver.json';
|
||||
|
||||
function getCommitHashFromVersionJson() {
|
||||
return Promise.attempt(function () {
|
||||
var configFile = path.join(__dirname, '..', 'config', 'version.json');
|
||||
if (fs.existsSync(configFile)) {
|
||||
var commitHash;
|
||||
try {
|
||||
commitHash = require(configFile).version.hash;
|
||||
} catch (e) {
|
||||
logger.error('could not read version.hash from version.json');
|
||||
}
|
||||
return commitHash;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getGitDir() {
|
||||
if (! fs.existsSync(path.join(__dirname, '..', '..', '..', '.git'))) {
|
||||
// try at '/home/app/git' for AwsBox deploys
|
||||
return path.sep + path.join('home', 'app', 'git');
|
||||
}
|
||||
}
|
||||
|
||||
function getCommitHashFromGit() {
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var gitDir = getGitDir();
|
||||
var cmd = util.format('git %s rev-parse HEAD', gitDir ? '--git-dir=' + gitDir : '');
|
||||
|
||||
child_process.exec(cmd, function (err, stdout) {
|
||||
deferred.resolve(stdout.replace(/\s+/, ''));
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
var promise;
|
||||
function getVersionInfo() {
|
||||
// only resolve once, the data does not need to be re-calculated.
|
||||
if (promise) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
// (1) read config/version.json if exists (ie. staging, production)
|
||||
promise = getCommitHashFromVersionJson()
|
||||
.then(function (commitHash) {
|
||||
if (commitHash) {
|
||||
return commitHash;
|
||||
}
|
||||
// (2) figure it out from git (either regular '.git',
|
||||
// or '/home/app/git' for AwsBox)
|
||||
return getCommitHashFromGit();
|
||||
})
|
||||
.then(function (commitHash) {
|
||||
logger.info('version set to: %s', version);
|
||||
logger.info('commit hash set to: %s', commitHash);
|
||||
return {
|
||||
version: version,
|
||||
commit: commitHash
|
||||
};
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
// seed the info on startup.
|
||||
getVersionInfo();
|
||||
|
||||
|
||||
exports.process = function (req, res) {
|
||||
getVersionInfo()
|
||||
.then(function (versionInfo) {
|
||||
// charset must be set on json responses.
|
||||
res.charset = 'utf8';
|
||||
res.json(versionInfo);
|
||||
});
|
||||
};
|
||||
|
|
@ -11,7 +11,11 @@ define([
|
|||
intern.webdriver = {};
|
||||
intern.environments = [];
|
||||
intern.functionalSuites = [];
|
||||
intern.suites = [ 'tests/server/templates', 'tests/server/routes' ];
|
||||
intern.suites = [
|
||||
'tests/server/templates',
|
||||
'tests/server/routes',
|
||||
'tests/server/ver.json.js'
|
||||
];
|
||||
|
||||
return intern;
|
||||
});
|
||||
|
|
|
@ -40,6 +40,7 @@ define([
|
|||
'/force_auth': 200,
|
||||
'/tests/index.html': 200,
|
||||
'/tests/index.html?coverage': 200,
|
||||
'/ver.json': 200,
|
||||
'/non_existent': 404
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
define([
|
||||
'intern!object',
|
||||
'intern/chai!assert',
|
||||
'intern/dojo/node!../../server/lib/configuration',
|
||||
'intern/dojo/node!request'
|
||||
], function (registerSuite, assert, config, request) {
|
||||
'use strict';
|
||||
|
||||
var serverUrl = config.get('public_url');
|
||||
|
||||
var suite = {
|
||||
name: 'ver.json'
|
||||
};
|
||||
|
||||
suite['#get ver.json'] = function () {
|
||||
var dfd = this.async(1000);
|
||||
|
||||
request(serverUrl + '/ver.json', dfd.callback(function (err, res) {
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.equal(res.headers['content-type'], 'application/json; charset=utf8');
|
||||
|
||||
var body = JSON.parse(res.body);
|
||||
assert.ok('version' in body);
|
||||
assert.ok('commit' in body);
|
||||
}, dfd.reject.bind(dfd)));
|
||||
};
|
||||
|
||||
registerSuite(suite);
|
||||
});
|
Загрузка…
Ссылка в новой задаче