Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: firebase/firebase-functions
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.13.0
Choose a base ref
...
head repository: firebase/firebase-functions
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.13.1
Choose a head ref
  • 6 commits
  • 10 files changed
  • 7 contributors

Commits on Dec 7, 2020

  1. Copy the full SHA
    c69c9bc View commit details

Commits on Jan 11, 2021

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9b8fe65 View commit details

Commits on Jan 13, 2021

  1. Add support for 4GB memory option (#842)

    * Add support for 4GB memory option
    
    The 4GB memory option was not added everywhere.
    
    Fixes #834
    
    * Added test for 4GB memory option
    
    Co-authored-by: Leon Radley <leon@wec360.se>
    Co-authored-by: joehan <joehanley@google.com>
    3 people authored Jan 13, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2f72c33 View commit details

Commits on Jan 15, 2021

  1. Remove circular dependencies when logging. Fixes #737 (#844)

    * Remove circular dependencies when logging. Fixes #737
    
    * Fix bug in binding the output logger
    
    * modify removeCircular to return a copy of the original object, rather than mutate
    
    * Modify removeCircular to return a new object, rather than mutating in place
    
    Co-authored-by: Michael Bleigh <bleigh@google.com>
    huangjeff5 and mbleigh authored Jan 15, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f508951 View commit details
  2. Add changelog entry for #842 (#845)

    * add changelog for memory options
    
    * formats
    
    * Update CHANGELOG.md
    
    * Update CHANGELOG.md
    
    Co-authored-by: huangjeff5 <64040981+huangjeff5@users.noreply.github.com>
    joehan and huangjeff5 authored Jan 15, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    e920b01 View commit details
  3. 3.13.1

    google-oss-bot committed Jan 15, 2021
    Copy the full SHA
    daeda1d View commit details
Showing with 129 additions and 54 deletions.
  1. +2 −18 CHANGELOG.md
  2. +1 −1 package-lock.json
  3. +2 −1 package.json
  4. +12 −0 spec/function-builder.spec.ts
  5. +56 −28 spec/logger.spec.ts
  6. +11 −0 spec/providers/database.spec.ts
  7. +1 −0 src/cloud-functions.ts
  8. +2 −2 src/function-builder.ts
  9. +33 −2 src/logger.ts
  10. +9 −2 src/providers/database.ts
20 changes: 2 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,2 @@
- Adds `serviceAccount` option to `runtimeOptions` to specify which service account Cloud Function should use at runtime. For example:

```
const functions = require('firebase-functions');
exports.myFunction = functions.runWith({
serviceAccount: 'test-sa@project.iam.gserviceaccount.com'
// OR
// serviceAcount: 'test-sa@"
// OR
// serviceAccount: 'default'
})
```

Requires firebase-tools@8.18.0 or later. Thanks @egor-miasnikov!

- Upgrades `highlight.js` to `10.4.1` to fix a vulnerability.
- Fixes a bug that prevented Functions from being deployed with `availableMemoryMb` set to `4GB`.
- Fixes bug where `functions.logger.log` crashes function if circular dependencies are passed in
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "firebase-functions",
"version": "3.13.0",
"version": "3.13.1",
"description": "Firebase SDK for Cloud Functions",
"keywords": [
"firebase",
@@ -31,6 +31,7 @@
"build:pack": "rm -rf lib && npm install && tsc -p tsconfig.release.json && npm pack",
"build:release": "npm install --production && npm install --no-save typescript firebase-admin && tsc -p tsconfig.release.json",
"build": "tsc -p tsconfig.release.json",
"build:watch": "npm run build -- -w",
"format": "prettier --check '**/*.{json,md,ts,yml,yaml}'",
"format:fix": "prettier --write '**/*.{json,md,ts,yml,yaml}'",
"lint": "tslint --config tslint.json --project tsconfig.json ",
12 changes: 12 additions & 0 deletions spec/function-builder.spec.ts
Original file line number Diff line number Diff line change
@@ -286,4 +286,16 @@ describe('FunctionBuilder', () => {
});
}).to.throw();
});

it('should allow setting 4GB memory option', () => {
const fn = functions
.runWith({
memory: '4GB',
})
.region('europe-west1')
.auth.user()
.onCreate((user) => user);

expect(fn.__trigger.availableMemoryMb).to.deep.equal(4096);
});
});
84 changes: 56 additions & 28 deletions spec/logger.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { expect } from 'chai';
import * as sinon from 'sinon';
import * as logger from '../src/logger';

const SUPPORTS_STRUCTURED_LOGS =
@@ -8,52 +7,51 @@ const SUPPORTS_STRUCTURED_LOGS =
describe(`logger (${
SUPPORTS_STRUCTURED_LOGS ? 'structured' : 'unstructured'
})`, () => {
let sandbox: sinon.SinonSandbox;
let stdoutStub: sinon.SinonStub;
let stderrStub: sinon.SinonStub;
let stdoutWrite = process.stdout.write.bind(process.stdout);
let stderrWrite = process.stderr.write.bind(process.stderr);
let lastOut: string;
let lastErr: string;

beforeEach(() => {
sandbox = sinon.createSandbox();
stdoutStub = sandbox.stub(process.stdout, 'write');
stderrStub = sandbox.stub(process.stderr, 'write');
process.stdout.write = (msg: Buffer | string, cb?: any): boolean => {
lastOut = msg as string;
return stdoutWrite(msg, cb);
};
process.stderr.write = (msg: Buffer | string, cb?: any): boolean => {
lastErr = msg as string;
return stderrWrite(msg, cb);
};
});

function expectOutput(stdStub: sinon.SinonStub, entry: any) {
afterEach(() => {
process.stdout.write = stdoutWrite;
process.stderr.write = stderrWrite;
});

function expectOutput(last: string, entry: any) {
if (SUPPORTS_STRUCTURED_LOGS) {
return expect(
JSON.parse((stdStub.getCalls()[0].args[0] as string).trim())
).to.deep.eq(entry);
return expect(JSON.parse(last.trim())).to.deep.eq(entry);
} else {
// legacy logging is not structured, but do a sanity check
return expect(stdStub.getCalls()[0].args[0]).to.include(entry.message);
return expect(last).to.include(entry.message);
}
}

function expectStdout(entry: any) {
return expectOutput(stdoutStub, entry);
return expectOutput(lastOut, entry);
}

function expectStderr(entry: any) {
return expectOutput(stderrStub, entry);
return expectOutput(lastErr, entry);
}

describe('logging methods', () => {
let writeStub: sinon.SinonStub;
beforeEach(() => {
writeStub = sinon.stub(logger, 'write');
});

afterEach(() => {
writeStub.restore();
});

it('should coalesce arguments into the message', () => {
logger.log('hello', { middle: 'obj' }, 'end message');
expectStdout({
severity: 'INFO',
message: "hello { middle: 'obj' } end message",
});
sandbox.restore(); // to avoid swallowing test runner output
});

it('should merge structured data from the last argument', () => {
@@ -63,7 +61,6 @@ describe(`logger (${
message: 'hello world',
additional: 'context',
});
sandbox.restore(); // to avoid swallowing test runner output
});

it('should not recognize null as a structured logging object', () => {
@@ -72,13 +69,46 @@ describe(`logger (${
severity: 'INFO',
message: 'hello world null',
});
sandbox.restore(); // to avoid swallowing test runner output
});
});

describe('write', () => {
describe('structured logging', () => {
describe('write', () => {
it('should remove circular references', () => {
const circ: any = { b: 'foo' };
circ.circ = circ;

const entry: logger.LogEntry = {
severity: 'ERROR',
message: 'testing circular',
circ,
};
logger.write(entry);
expectStderr({
severity: 'ERROR',
message: 'testing circular',
circ: { b: 'foo', circ: '[Circular]' },
});
});

it('should remove circular references in arrays', () => {
const circ: any = { b: 'foo' };
circ.circ = [circ];

const entry: logger.LogEntry = {
severity: 'ERROR',
message: 'testing circular',
circ,
};
logger.write(entry);
expectStderr({
severity: 'ERROR',
message: 'testing circular',
circ: { b: 'foo', circ: ['[Circular]'] },
});
});

for (const severity of ['DEBUG', 'INFO', 'NOTICE']) {
it(`should output ${severity} severity to stdout`, () => {
let entry: logger.LogEntry = {
@@ -87,7 +117,6 @@ describe(`logger (${
};
logger.write(entry);
expectStdout(entry);
sandbox.restore(); // to avoid swallowing test runner output
});
}

@@ -105,7 +134,6 @@ describe(`logger (${
};
logger.write(entry);
expectStderr(entry);
sandbox.restore(); // to avoid swallowing test runner output
});
}
});
11 changes: 11 additions & 0 deletions spec/providers/database.spec.ts
Original file line number Diff line number Diff line change
@@ -472,6 +472,17 @@ describe('Database Functions', () => {
);
}).to.throw(Error);
});

it('should use the emulator host when present', () => {
process.env.FIREBASE_DATABASE_EMULATOR_HOST = 'localhost:1234';
const [instance, path] = database.extractInstanceAndPath(
'projects/_/instances/foo/refs/bar',
'firebaseio-staging.com'
);
expect(instance).to.equal('http://localhost:1234/?ns=foo');
expect(path).to.equal('/bar');
delete process.env.FIREBASE_DATABASE_EMULATOR_HOST;
});
});

describe('DataSnapshot', () => {
1 change: 1 addition & 0 deletions src/cloud-functions.ts
Original file line number Diff line number Diff line change
@@ -507,6 +507,7 @@ export function optionsToTrigger(options: DeploymentOptions) {
'512MB': 512,
'1GB': 1024,
'2GB': 2048,
'4GB': 4096,
};
trigger.availableMemoryMb = _.get(memoryLookup, options.memory);
}
4 changes: 2 additions & 2 deletions src/function-builder.ts
Original file line number Diff line number Diff line change
@@ -144,7 +144,7 @@ export function region(
* Configure runtime options for the function.
* @param runtimeOptions Object with optional fields:
* 1. `memory`: amount of memory to allocate to the function, possible values
* are: '128MB', '256MB', '512MB', '1GB', and '2GB'.
* are: '128MB', '256MB', '512MB', '1GB', '2GB', and '4GB'.
* 2. `timeoutSeconds`: timeout for the function in seconds, possible values are
* 0 to 540.
* 3. `failurePolicy`: failure policy of the function, with boolean `true` being
@@ -188,7 +188,7 @@ export class FunctionBuilder {
* Configure runtime options for the function.
* @param runtimeOptions Object with optional fields:
* 1. `memory`: amount of memory to allocate to the function, possible values
* are: '128MB', '256MB', '512MB', '1GB', and '2GB'.
* are: '128MB', '256MB', '512MB', '1GB', '2GB', and '4GB'.
* 2. `timeoutSeconds`: timeout for the function in seconds, possible values are
* 0 to 540.
* 3. `failurePolicy`: failure policy of the function, with boolean `true` being
35 changes: 33 additions & 2 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -30,13 +30,40 @@ export interface LogEntry {
[key: string]: any;
}

function removeCircular(obj: any, refs: any[] = []): any {
if (typeof obj !== 'object' || !obj) {
return obj;
}
if (refs.includes(obj)) {
return '[Circular]';
} else {
refs.push(obj);
}
let returnObj: any;
if (Array.isArray(obj)) {
returnObj = new Array(obj.length);
} else {
returnObj = {};
}
for (const k in obj) {
if (refs.includes(obj[k])) {
returnObj[k] = '[Circular]';
} else {
returnObj[k] = removeCircular(obj[k], refs);
}
}
return returnObj;
}

/**
* Writes a `LogEntry` to `stdout`/`stderr` (depending on severity).
* @param entry The `LogEntry` including severity, message, and any additional structured metadata.
*/
export function write(entry: LogEntry) {
if (SUPPORTS_STRUCTURED_LOGS) {
UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]](JSON.stringify(entry));
UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]](
JSON.stringify(removeCircular(entry))
);
return;
}

@@ -50,7 +77,11 @@ export function write(entry: LogEntry) {
}
}
if (jsonKeyCount > 0) {
message = `${message} ${JSON.stringify(jsonPayload, null, 2)}`;
message = `${message} ${JSON.stringify(
removeCircular(jsonPayload),
null,
2
)}`;
}
UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]](message);
}
11 changes: 9 additions & 2 deletions src/providers/database.ts
Original file line number Diff line number Diff line change
@@ -334,8 +334,15 @@ export function extractInstanceAndPath(
`Expect project to be '_' in a Firebase Realtime Database event`
);
}
const dbInstance = 'https://' + dbInstanceName + '.' + domain;
return [dbInstance, path];

const emuHost = process.env.FIREBASE_DATABASE_EMULATOR_HOST;
if (emuHost) {
const dbInstance = `http://${emuHost}/?ns=${dbInstanceName}`;
return [dbInstance, path];
} else {
const dbInstance = 'https://' + dbInstanceName + '.' + domain;
return [dbInstance, path];
}
}

/**