mirror of
https://github.com/zhigang1992/firebase-tools.git
synced 2026-04-28 20:05:23 +08:00
Update functions emulator to beta.3 version (#255)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
19
lib/getProjectNumber.js
Normal 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;
|
||||
});
|
||||
};
|
||||
@@ -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) {
|
||||
|
||||
30
lib/utils.js
30
lib/utils.js
@@ -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]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user