Skip to content

Commit

Permalink
Merge branch 'master' into dt-node-upgrades
Browse files Browse the repository at this point in the history
  • Loading branch information
thechenky committed May 2, 2019
2 parents 8422201 + 75c3106 commit 41c6f09
Show file tree
Hide file tree
Showing 14 changed files with 224 additions and 98 deletions.
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
feature - Node 10 support for Cloud Functions for Firebase.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
"tmp": "0.0.33",
"universal-analytics": "^0.4.16",
"update-notifier": "^2.5.0",
"user-home": "^2.0.0",
"uuid": "^3.0.0",
"winston": "^1.0.1"
},
Expand All @@ -113,7 +112,9 @@
"@types/node": "^10.12.0",
"@types/opn": "~5.1.0",
"@types/request": "^2.48.1",
"@types/semver": "^6.0.0",
"@types/sinon": "^5.0.5",
"@types/sinon-chai": "^3.2.2",
"@types/supertest": "^2.0.6",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

var clc = require("cli-color");
var fs = require("fs");
var homeDir = require("user-home");
var homeDir = require("os").homedir();
var path = require("path");

var Command = require("../command");
Expand Down
7 changes: 4 additions & 3 deletions src/deploy/functions/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var logger = require("../../logger");
var track = require("../../track");
var utils = require("../../utils");
var helper = require("../../functionsDeployHelper");
var runtimeSelector = require("../../runtimeChoiceSelector");
var { getAppEngineLocation } = require("../../functionsConfig");
var prompt = require("../../prompt");
var { createOrUpdateSchedulesAndTopics } = require("./createOrUpdateSchedulesAndTopics");
Expand Down Expand Up @@ -170,11 +171,11 @@ module.exports = function(context, options, payload) {
var functionTrigger = helper.getFunctionTrigger(functionInfo);
var functionName = helper.getFunctionName(name);
var region = helper.getRegion(name);
var runtime = context.runtimeChoice || helper.getDefaultRuntime(options);
var runtime = context.runtimeChoice || helper.getDefaultRuntime();
utils.logBullet(
clc.bold.cyan("functions: ") +
"creating " +
helper.getRuntimeName(runtime) +
runtimeSelector.getHumanFriendlyRuntimeName(runtime) +
" function " +
clc.bold(helper.getFunctionLabel(name)) +
"..."
Expand Down Expand Up @@ -265,7 +266,7 @@ module.exports = function(context, options, payload) {
utils.logBullet(
clc.bold.cyan("functions: ") +
"updating " +
helper.getRuntimeName(runtime) +
runtimeSelector.getHumanFriendlyRuntimeName(runtime) +
" function " +
clc.bold(helper.getFunctionLabel(name)) +
"..."
Expand Down
2 changes: 1 addition & 1 deletion src/emulator/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

var userHome = require("user-home");
var userHome = require("os").homedir();
var path = require("path");

const CACHE_DIR =
Expand Down
52 changes: 9 additions & 43 deletions src/functionsDeployHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,50 +208,17 @@ function pollDeploys(operations, printSuccess, printFail, printTooManyOps, proje
});
}

function getRuntimeName(runtime) {
if (runtime === "nodejs8") {
return "Node.js 8";
}
if (runtime === "nodejs6") {
return "Node.js 6";
}
return runtime;
}

function getDefaultRuntime() {
// TODO uncomment when Node.js v8 is the default.
/**
function getDefaultRuntime(options)
var packageJsonPath = path.join(
options.config.path(options.config.get("functions.source")),
"package.json"
logger.info();
utils.logWarning(
clc.bold.yellow(
"functions: WARNING! NO ENGINES FIELD FOUND IN PACKAGE.JSON. DEFAULTING TO NODE 6 RUNTIME. " +
"Starting June 1, 2019 deployments will be blocked if no engines field is specified in package.json. " +
"To fix this, add the following lines to your package.json:\n\n" +
'"engines": {\n "node": "6" \n}'
)
);
var loaded = require(packageJsonPath);
var SDKRange = _.get(loaded, "dependencies.firebase-functions");
try {
if (!semver.intersects(SDKRange, ">=2")) {
utils.logWarning(
clc.bold.yellow("functions: ") +
"Deploying functions to Node 6 runtime. Please note that Node 8 is also available and is the recommended runtime. " +
"However, you must have a " +
clc.bold("firebase-functions") +
" version that is at least 2.0.0. Please run " +
clc.bold("npm i --save firebase-functions@latest") +
" in the functions folder and add an " +
clc.bold("engines") +
" field to " +
clc.bold("functions/package.json") +
" with the value " +
clc.bold('{"node": "8"}')
);
return "nodejs6";
}
return "nodejs8";
} catch (e) {
// semver check will fail if a URL is used instead of a version number, in that case stay safe and return Node 6 as default.
return "nodejs6";
}
**/
logger.info();
return "nodejs6";
}

Expand All @@ -268,6 +235,5 @@ module.exports = {
functionMatchesGroup: functionMatchesGroup,
getFunctionLabel: getFunctionLabel,
pollDeploys: pollDeploys,
getRuntimeName: getRuntimeName,
getDefaultRuntime: getDefaultRuntime,
};
47 changes: 2 additions & 45 deletions src/prepareFunctionsUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ var clc = require("cli-color");
var filesize = require("filesize");
var fs = require("fs");
var path = require("path");
var semver = require("semver");
var tmp = require("tmp");

var FirebaseError = require("./error");
Expand All @@ -16,6 +15,7 @@ var logger = require("./logger");
var utils = require("./utils");
var parseTriggers = require("./parseTriggers");
var fsAsync = require("./fsAsync");
var { getRuntimeChoice } = require("./runtimeChoiceSelector");

var CONFIG_DEST_FILE = ".runtimeconfig.json";

Expand Down Expand Up @@ -110,53 +110,10 @@ var _packageSource = function(options, sourceDir, configValues) {
);
};

var _getRuntimeChoice = function(sourceDir) {
var packageJsonPath = path.join(sourceDir, "package.json");
var loaded = require(packageJsonPath);
var choice = loaded.engines;
if (!choice) {
return null;
}
if (_.isEqual(choice, { node: "6" })) {
return "nodejs6";
}
if (_.isEqual(choice, { node: "8" })) {
var SDKRange = _.get(loaded, "dependencies.firebase-functions");
try {
if (!semver.intersects(SDKRange, ">=2")) {
throw new FirebaseError(
"You must have a firebase-functions version that is at least 1.1.0 " +
"in order to deploy functions to the Node 8 runtime.\nPlease run " +
clc.bold("npm i --save firebase-functions@latest") +
" in the functions folder.",
{
exit: 1,
}
);
}
} catch (e) {
// semver check will fail if a URL is used instead of a version number, do nothing
}
return "nodejs8";
}
throw new FirebaseError(
clc.bold("package.json") +
" in functions directory has an engines field which is unsupported." +
" The only valid choices are: " +
clc.bold('{"node": "8"}') +
" and " +
clc.bold('{"node": "6"}') +
".",
{
exit: 1,
}
);
};

module.exports = function(context, options) {
var configValues;
var sourceDir = options.config.path(options.config.get("functions.source"));
context.runtimeChoice = _getRuntimeChoice(sourceDir);
context.runtimeChoice = getRuntimeChoice(sourceDir);
return _getFunctionsConfig(context)
.then(function(result) {
configValues = result;
Expand Down
96 changes: 96 additions & 0 deletions src/runtimeChoiceSelector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as _ from "lodash";
import * as path from "path";
import * as clc from "cli-color";
import * as semver from "semver";

import * as FirebaseError from "./error";
import * as utils from "./utils";

// have to require this because no @types/cjson available
// tslint:disable-next-line
var cjson = require("cjson");

const MESSAGE_FRIENDLY_RUNTIMES: { [key: string]: string } = {
nodejs6: "Node.js 6 (Deprecated)",
nodejs8: "Node.js 8",
nodejs10: "Node.js 10 (Beta)",
};

const ENGINE_RUNTIMES: { [key: string]: string } = {
6: "nodejs6",
8: "nodejs8",
10: "nodejs10",
};

export const ENGINES_FIELD_REQUIRED_MSG = clc.bold(
"Engines field is required in package.json but none was found."
);
export const UNSUPPORTED_NODE_VERSION_MSG = clc.bold(
`package.json in functions directory has an engines field which is unsupported. ` +
`The only valid choices are: ${clc.bold('{"node": "8"}')} and ${clc.bold('{"node": "10"}')}. ` +
`Note that Node.js 6 is now deprecated.`
);
export const DEPRECATION_WARNING_MSG =
clc.bold.yellow("functions: ") +
"Deploying functions to Node 6 runtime, which is deprecated. Node 8 is available " +
"and is the recommended runtime.";

export const FUNCTIONS_SDK_VERSION_TOO_OLD_WARNING =
clc.bold.yellow("functions: ") +
"You must have a " +
clc.bold("firebase-functions") +
" version that is at least 2.0.0. Please run " +
clc.bold("npm i --save firebase-functions@latest") +
" in the functions folder.";

/**
* Returns a friendly string denoting the chosen runtime: Node.js 8 for nodejs 8
* for example. If no friendly name for runtime is found, returns back the raw runtime.
* @param runtime name of runtime in raw format, ie, "nodejs8" or "nodejs10"
*/
export function getHumanFriendlyRuntimeName(runtime: string): string {
return _.get(MESSAGE_FRIENDLY_RUNTIMES, runtime, runtime);
}

/**
* Returns the Node.js version to be used for the function(s) as defined in the
* package.json.
* @param sourceDir directory where the functions are defined.
*/
export function getRuntimeChoice(sourceDir: string): any {
const packageJsonPath = path.join(sourceDir, "package.json");
const loaded = cjson.load(packageJsonPath);
const engines = loaded.engines;
if (!engines || !engines.node) {
return null;
// TODO(b/129422952): Change to throw error instead of returning null
// when engines field in package.json becomes required:
// throw new FirebaseError(ENGINES_FIELD_REQUIRED_MSG, { exit: 1 });
}
const runtime = ENGINE_RUNTIMES[engines.node];
if (!runtime) {
throw new FirebaseError(UNSUPPORTED_NODE_VERSION_MSG, { exit: 1 });
}

if (runtime === "nodejs6") {
utils.logWarning(DEPRECATION_WARNING_MSG);
} else {
// for any other runtime (8 or 10)
if (functionsSDKTooOld(loaded)) {
utils.logWarning(FUNCTIONS_SDK_VERSION_TOO_OLD_WARNING);
}
}
return runtime;
}

function functionsSDKTooOld(loaded: any): boolean {
const SDKRange = _.get(loaded, "dependencies.firebase-functions");
try {
if (!semver.intersects(SDKRange, ">=2")) {
return true;
}
} catch (e) {
// do nothing
}
return false;
}
2 changes: 2 additions & 0 deletions src/test/helpers/mocha-bootstrap.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const chai = require("chai");
const chaiAsPromised = require("chai-as-promised");
const sinonChai = require("sinon-chai");

chai.use(chaiAsPromised);
chai.use(sinonChai);

process.on("unhandledRejection", (error) => {
throw error;
Expand Down
Loading

0 comments on commit 41c6f09

Please sign in to comment.