Update functions emulator to beta.3 version (#255)

This commit is contained in:
Lauren Long
2018-03-01 13:35:47 -06:00
committed by GitHub
parent 0a101cad34
commit 1704870153
13 changed files with 86 additions and 84 deletions

View File

@@ -11,6 +11,7 @@ var checkDupHostingKeys = require('../lib/checkDupHostingKeys');
var serve = require('../lib/serve/index');
var scopes = require('../lib/scopes');
var filterTargets = require('../lib/filterTargets');
var getProjectNumber = require('../lib/getProjectNumber');
var VALID_TARGETS = ['functions', 'hosting'];
@@ -23,6 +24,7 @@ module.exports = new Command('serve')
.before(requireConfig)
.before(requireAccess, [scopes.CLOUD_PLATFORM])
.before(checkDupHostingKeys)
.before(getProjectNumber)
.action(function(options) {
if (options.config) {
logger.info();

View File

@@ -81,7 +81,6 @@ var api = {
clientSecret: utils.envOverride('FIREBASE_CLIENT_SECRET', 'j9iVZfS8kkCEFUPaAeJV0sAi'),
cloudloggingOrigin: utils.envOverride('FIREBASE_CLOUDLOGGING_URL', 'https://logging.googleapis.com'),
adminOrigin: utils.envOverride('FIREBASE_ADMIN_URL', 'https://admin.firebase.com'),
apikeysOrigin: utils.envOverride('FIREBASE_APIKEYS_URL', 'https://apikeys.googleapis.com'),
appengineOrigin: utils.envOverride('FIREBASE_APPENGINE_URL', 'https://appengine.googleapis.com'),
authOrigin: utils.envOverride('FIREBASE_AUTH_URL', 'https://accounts.google.com'),
consoleOrigin: utils.envOverride('FIREBASE_CONSOLE_URL', 'https://console.firebase.google.com'),

View File

@@ -56,13 +56,12 @@ module.exports = function(context, options, payload) {
return utils.reject('No npm package found in functions source directory. Please run \'npm init\' inside ' + sourceDirName, {exit: 1});
}
var projectId = getProjectId(options);
var instance = options.instance;
return RSVP.all([
ensureApiEnabled.ensure(options.project, 'cloudfunctions.googleapis.com', 'functions'),
ensureApiEnabled.check(projectId, 'runtimeconfig.googleapis.com', 'runtimeconfig', true)
]).then(function(results) {
_.set(context, 'runtimeConfigEnabled', results[1]);
return functionsConfig.getFirebaseConfig(projectId, instance);
return functionsConfig.getFirebaseConfig(options);
}).then(function(result) {
_.set(context, 'firebaseConfig', result);
_.set(context, 'functionsBucket', 'staging.' + result.storageBucket);

View File

@@ -5,7 +5,6 @@ var path = require('path');
var api = require('./api');
var configstore = require('./configstore');
var fsutils = require('./fsutils');
var logger = require('./logger');
var configDir = function() {
@@ -29,7 +28,6 @@ module.exports = function() {
var GCLOUD_CREDENTIAL_DIR = path.resolve(configDir(), 'gcloud');
var GCLOUD_CREDENTIAL_PATH = path.join(GCLOUD_CREDENTIAL_DIR, 'application_default_credentials.json');
if (fsutils.fileExistsSync(GCLOUD_CREDENTIAL_PATH)) { return; }
var credentials = {
client_id: api.clientId,
client_secret: api.clientSecret,

View File

@@ -1,15 +1,11 @@
'use strict';
var getProjectId = require('./getProjectId');
var getProjectNumber = require('./getProjectNumber');
var api = require('./api');
module.exports = function(options) {
var projectId = getProjectId(options);
return api.request('GET', '/v1/projects/' + projectId, {
auth: true,
origin: api.resourceManagerOrigin
}).then(function(response) {
return api.request('GET', '/v1/projects/' + response.body.projectNumber + '/clients/_:getWebAppConfig', {
return getProjectNumber(options).then(function(projectNumber) {
return api.request('GET', '/v1/projects/' + projectNumber + '/clients/_:getWebAppConfig', {
auth: true,
origin: api.firedataOrigin
});

View File

@@ -6,11 +6,9 @@ var chalk = require('chalk');
var api = require('./api');
var FirebaseError = require('./error');
var runtimeconfig = require('./gcp/runtimeconfig');
var storage = require('./gcp/storage');
var apikeys = require('./gcp/apikeys');
var getProjectId = require('./getProjectId');
var getProjectNumber = require('./getProjectNumber');
var ensureApiEnabled = require('./ensureApiEnabled').ensure;
var utils = require('./utils');
exports.RESERVED_NAMESPACES = ['firebase'];
@@ -47,20 +45,18 @@ exports.idsToVarName = function(projectId, configId, varId) {
return _.join(['projects', projectId, 'configs', configId, 'variables', varId], '/');
};
exports.getFirebaseConfig = function(projectId, instance) {
return RSVP.all([storage.buckets.getDefault(projectId), apikeys.getServerKey(projectId)])
.then(function(results) {
return {
databaseURL: utils.addSubdomain(api.realtimeOrigin, instance),
storageBucket: results[0],
apiKey: results[1],
authDomain: instance + '.firebaseapp.com',
projectId: projectId
};
exports.getFirebaseConfig = function(options) {
return getProjectNumber(options)
.then(function(projectNumber) {
return api.request('GET', '/v1/projects/' + projectNumber + ':getServerAppConfig', {
auth: true,
origin: api.firedataOrigin
});
}).then(function(response) {
return response.body;
});
};
// If you make changes to this function, run "node scripts/test-functions-config.js"
// to ensure that nothing broke.
exports.setVariablesRecursive = function(projectId, configId, varPath, val) {

View File

@@ -45,13 +45,8 @@ var _pollOperation = function(op, controller) {
});
};
var _getProviderString = function(eventType) {
var provider = _.last(eventType.split('/')[1].split('.'));
return _.capitalize(provider);
};
FunctionsEmulator.prototype.stop = function() {
delete process.env.FIREBASE_PROJECT;
delete process.env.FIREBASE_CONFIG;
delete process.env.GCLOUD_PROJECT;
var controller = this.controller;
return new RSVP.Promise(function(resolve) {
@@ -112,10 +107,9 @@ FunctionsEmulator.prototype.start = function(shellMode) {
utils.logBullet(chalk.cyan.bold('functions:') + ' Preparing to emulate functions.');
logger.debug('Fetching environment');
ensureDefaultCredentials();
return functionsConfig.getFirebaseConfig(projectId, options.instance)
return functionsConfig.getFirebaseConfig(options)
.then(function(result) {
firebaseConfig = JSON.stringify(result);
process.env.FIREBASE_PROJECT = firebaseConfig;
process.env.FIREBASE_CONFIG = JSON.stringify(result);
process.env.GCLOUD_PROJECT = projectId;
logger.debug('Starting @google-cloud/functions-emulator');
return controller.start();
@@ -125,38 +119,39 @@ FunctionsEmulator.prototype.start = function(shellMode) {
utils.logWarning(chalk.yellow('functions:') + ' Failed to load functions source code. ' +
'Ensure that you have the latest SDK by running ' + chalk.bold('npm i --save firebase-functions') +
' inside the functions directory.');
return RSVP.reject(e);
logger.debug('Error during trigger parsing: ', e.message);
return RSVP.reject(e.message);
});
}).then(function(triggers) {
instance.triggers = triggers;
var promises = _.map(triggers, function(trigger) {
if (trigger.httpsTrigger) {
return controller.deploy(trigger.name, {
localPath: functionsDir,
source: functionsDir,
triggerHttp: true
}).catch(function() {
}).catch(function(e) {
logger.debug('Error while deploy to emulator: ' + e.stack);
return RSVP.reject({name: trigger.name});
});
}
if (!shellMode) {
return RSVP.resolve(); // Don't emulate non-HTTPS functions if shell not running
}
var parts = trigger.eventTrigger.eventType.split('/');
var triggerProvider = parts[1];
var triggerEvent = parts[3];
logger.debug('Deploying functions locally');
return controller.deploy(trigger.name, {
localPath: functionsDir,
triggerProvider: triggerProvider,
triggerEvent: triggerEvent,
triggerResource: trigger.eventTrigger.resource
eventType: trigger.eventTrigger.eventType,
resource: trigger.eventTrigger.resource,
source: functionsDir
}).catch(function(e) {
logger.debug('Error while deploy to emulator: ' + e.stack);
return RSVP.reject({name: trigger.name});
});
});
return RSVP.allSettled(promises);
}).then(function(operations) {
return RSVP.all(_.map(operations, function(operation) {
if (operation.state === 'rejected') {
utils.logWarning(chalk.yellow('functions:') + ' Failed to emulate ' + operation.reason.name);
utils.logWarning(chalk.yellow('functions:') + ' Failed to emulate ' + _.get(operation, 'reason.name', ''));
return RSVP.resolve();
}
if (!operation.value) {
@@ -174,7 +169,7 @@ FunctionsEmulator.prototype.start = function(shellMode) {
}
utils.logSuccess(message);
} else {
var provider = _getProviderString(res.eventTrigger.eventType);
var provider = utils.getFunctionsEventProvider(res.eventTrigger.eventType);
emulatedProviders[provider] = true;
utils.logSuccess(chalk.green.bold('functions: ') + funcName);
}
@@ -190,6 +185,7 @@ FunctionsEmulator.prototype.start = function(shellMode) {
}).catch(function(e) {
if (e) {
utils.logWarning(chalk.yellow('functions:') + ' Error from emulator. ' + e);
logger.debug(e.stack);
}
return instance.stop();
});

View File

@@ -1,33 +0,0 @@
'use strict';
var api = require('../api');
var _ = require('lodash');
var RSVP = require('rsvp');
var logger = require('../logger');
var version = 'v1';
function _getKeys(projectId) {
return api.request('GET', '/' + version + '/projects/' + projectId + '/apiKeys', {
auth: true,
origin: api.apikeysOrigin
}).then(function(res) {
return res.body.keys;
});
}
function _getServerKey(projectId) {
return _getKeys(projectId).then(function(keys) {
var filter = function(elem) {
return /[Ss]erver/.test(elem.displayName);
};
return _.chain(keys).find(filter).get('currentKey').value();
}).catch(function(err) {
logger.debug('Error fetching server API key: ', err);
return RSVP.resolve(null);
});
}
module.exports = {
getServerKey: _getServerKey
};

View File

@@ -1,7 +1,6 @@
'use strict';
module.exports = {
apikeys: require('./apikeys'),
cloudfunctions: require('./cloudfunctions'),
cloudlogging: require('./cloudlogging'),
storage: require('./storage'),

19
lib/getProjectNumber.js Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
var getProjectId = require('./getProjectId');
var api = require('./api');
var RSVP = require('rsvp');
module.exports = function(options) {
if (options.projectNumber) {
return RSVP.resolve(options.projectNumber);
}
var projectId = getProjectId(options);
return api.request('GET', '/v1/projects/' + projectId, {
auth: true,
origin: api.resourceManagerOrigin
}).then(function(response) {
options.projectNumber = response.body.projectNumber;
return options.projectNumber;
});
};

View File

@@ -4,6 +4,7 @@ var _ = require('lodash');
var request = require('request');
var encodeFirestoreValue = require('./firestore/encodeFirestoreValue');
var utils = require('./utils');
var LocalFunction = function(trigger, urls, controller) {
this.name = trigger.name;
@@ -22,11 +23,11 @@ var LocalFunction = function(trigger, urls, controller) {
};
LocalFunction.prototype._isDatabaseFunc = function(eventTrigger) {
return _.includes(eventTrigger.eventType, 'firebase.database');
return utils.getFunctionsEventProvider(eventTrigger.eventType) === 'Database';
};
LocalFunction.prototype._isFirestoreFunc = function(eventTrigger) {
return _.includes(eventTrigger.eventType, 'cloud.firestore');
return utils.getFunctionsEventProvider(eventTrigger.eventType) === 'Firestore';
};
LocalFunction.prototype._substituteParams = function(resource, params) {

View File

@@ -162,5 +162,35 @@ module.exports = {
*/
endpoint: function(parts) {
return '/' + _.join(parts, '/');
},
/**
* Gets the event provider name for a Cloud Function from the trigger's eventType string.
* @param {String} eventType string from an event trigger
*/
getFunctionsEventProvider: function(eventType) {
// Legacy event types:
var parts = eventType.split('/');
if (parts.length > 1) {
var provider = _.last(parts[1].split('.'));
return _.capitalize(provider);
}
// New event types:
if (eventType.match(/google.pubsub/)) {
return 'PubSub';
} else if (eventType.match(/google.storage/)) {
return 'Storage';
} else if (eventType.match(/google.analytics/)) {
return 'Analytics';
} else if (eventType.match(/google.firebase.database/)) {
return 'Database';
} else if (eventType.match(/google.firebase.auth/)) {
return 'Auth';
} else if (eventType.match(/google.firebase.crashlytics/)) {
return 'Crashlytics';
} else if (eventType.match(/google.firestore/)) {
return 'Firestore';
}
return _.capitalize(eventType.split('.')[1]);
}
};

View File

@@ -99,6 +99,6 @@
"sinon-chai": "^2.8.0"
},
"optionalDependencies": {
"@google-cloud/functions-emulator": "1.0.0-alpha.23"
"@google-cloud/functions-emulator": "^1.0.0-beta.3"
}
}