FirebaseExtended / firestore-codelab-extended-swift

Apache License 2.0
48 stars 36 forks source link

Running `firebase deploy` results in Error: functions predeploy error: Command terminated with non-zero exit code2 #33

Open iamuzo opened 4 years ago

iamuzo commented 4 years ago

Device: MacBook Pro

Operating system version: macOS Catalina (version 10.15.1)

Swift version:

Node Version:

Firebase --version

What steps will reproduce the problem:

  1. Clone project
  2. Follow project steps as outlined in
  3. Step 3 in Part 9 Create a Cloud Function results in an error.

What is the expected result?

What happens instead of that?

running firebase deploy results in error with terminal output:

› firebase deploy 

=== Deploying to 'myfriendlyeats-625e0'...

i  deploying functions
Running command: npm --prefix $RESOURCE_DIR run lint

> functions@ lint /Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift/functions
> tslint -p tslint.json

Running command: npm --prefix $RESOURCE_DIR run build

> functions@ build /Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift/functions
> tsc

node_modules/firebase-functions/lib/function-configuration.d.ts:4:64 - error TS1005: ']' expected.

4 export declare const SUPPORTED_REGIONS: readonly ["us-central1", "us-east1", "us-east4", "europe-west1", "europe-west2", "asia-east2", "asia-northeast1"];
                                                                 ~

node_modules/firebase-functions/lib/function-configuration.d.ts:4:66 - error TS1134: Variable declaration expected.

4 export declare const SUPPORTED_REGIONS: readonly ["us-central1", "us-east1", "us-east4", "europe-west1", "europe-west2", "asia-east2", "asia-northeast1"];
                                                                   ~~~~~~~~~~

node_modules/firebase-functions/lib/function-configuration.d.ts:4:153 - error TS1005: ';' expected.

4 export declare const SUPPORTED_REGIONS: readonly ["us-central1", "us-east1", "us-east4", "europe-west1", "europe-west2", "asia-east2", "asia-northeast1"];
                                                                                                                                                          ~

node_modules/firebase-functions/lib/function-configuration.d.ts:16:61 - error TS1005: ']' expected.

16 export declare const VALID_MEMORY_OPTIONS: readonly ["128MB", "256MB", "512MB", "1GB", "2GB"];
                                                               ~

node_modules/firebase-functions/lib/function-configuration.d.ts:16:63 - error TS1134: Variable declaration expected.

16 export declare const VALID_MEMORY_OPTIONS: readonly ["128MB", "256MB", "512MB", "1GB", "2GB"];
                                                                 ~~~~~~~

node_modules/firebase-functions/lib/function-configuration.d.ts:16:93 - error TS1005: ';' expected.

16 export declare const VALID_MEMORY_OPTIONS: readonly ["128MB", "256MB", "512MB", "1GB", "2GB"];
                                                                                               ~

npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! functions@ build: `tsc`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the functions@ build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/uzo/.npm/_logs/2019-12-18T02_09_55_474Z-debug.log

Error: functions predeploy error: Command terminated with non-zero exit code2
Contents of debug.log
0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   '/Users/uzo/.nvm/versions/node/v12.14.0/bin/node',
1 verbose cli   '/Users/uzo/.nvm/versions/node/v12.14.0/bin/npm',
1 verbose cli   '--prefix',
1 verbose cli   '/Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift/functions',
1 verbose cli   'run',
1 verbose cli   'build'
1 verbose cli ]
2 info using npm@6.13.4
3 info using node@v12.14.0
4 verbose run-script [ 'prebuild', 'build', 'postbuild' ]
5 info lifecycle functions@~prebuild: functions@
6 info lifecycle functions@~build: functions@
7 verbose lifecycle functions@~build: unsafe-perm in lifecycle true
8 verbose lifecycle functions@~build: PATH: /Users/uzo/.nvm/versions/node/v12.14.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift/functions/node_modules/.bin:/Users/uzo/.rvm/gems/ruby-2.6.3/bin:/Users/uzo/.rvm/gems/ruby-2.6.3@global/bin:/Users/uzo/.rvm/rubies/ruby-2.6.3/bin:/Users/uzo/.nvm/versions/node/v12.14.0/bin:/Users/uzo/.gem/bin:/Users/uzo/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/uzo/.rvm/bin
9 verbose lifecycle functions@~build: CWD: /Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift/functions
10 silly lifecycle functions@~build: Args: [ '-c', 'tsc' ]
11 silly lifecycle functions@~build: Returned: code: 2  signal: null
12 info lifecycle functions@~build: Failed to exec build script
13 verbose stack Error: functions@ build: `tsc`
13 verbose stack Exit status 2
13 verbose stack     at EventEmitter.<anonymous> (/Users/uzo/.nvm/versions/node/v12.14.0/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16)
13 verbose stack     at EventEmitter.emit (events.js:210:5)
13 verbose stack     at ChildProcess.<anonymous> (/Users/uzo/.nvm/versions/node/v12.14.0/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
13 verbose stack     at ChildProcess.emit (events.js:210:5)
13 verbose stack     at maybeClose (internal/child_process.js:1021:16)
13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:283:5)
14 verbose pkgid functions@
15 verbose cwd /Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift
16 verbose Darwin 19.0.0
17 verbose argv "/Users/uzo/.nvm/versions/node/v12.14.0/bin/node" "/Users/uzo/.nvm/versions/node/v12.14.0/bin/npm" "--prefix" "/Users/uzo/Code/Learning/personal/firestore-codelab-extended-swift/functions" "run" "build"
18 verbose node v12.14.0
19 verbose npm  v6.13.4
20 error code ELIFECYCLE
21 error errno 2
22 error functions@ build: `tsc`
22 error Exit status 2
23 error Failed at the functions@ build script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 2, true ]
morganchen12 commented 4 years ago

Looks like this is the same error as https://github.com/firebase/firebase-functions/issues/404. It's a really long and messy thread, so you don't have to read the whole thing, but the cause of the error is you're running a different version of typescript than the one that Functions expects.

Can you share the versions in your package.json file?

iamuzo commented 4 years ago

@morganchen12 : I resolved my issue using 3 steps:

  1. I updated my package.json file to use firebase-admin version 8.0.0 and above. My package.json file currently looks like this:

    {
    "name": "functions",
    "scripts": {
    "lint": "./node_modules/.bin/tslint -p tslint.json",
    "build": "./node_modules/.bin/tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase experimental:functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
    },
    "main": "lib/index.js",
    "dependencies": {
    "firebase-admin": "^8.0.0",
    "firebase-functions": "^3.3.0"
    },
    "devDependencies": {
    "tslint": "^5.20.0",
    "typescript": "^2.9.2"
    },
    "private": true,
    "engines": {
    "node": "8"
    }
    }
  2. Added the additional step of running npm run build as suggested in firebase/firestore-codelab-extended-swift/issues/27

After this change, running firebase deploy resulted in new error messages:

src/index.ts:27:20 - error TS2532: Object is possibly 'undefined'.

27     const rating = eventData.rating;
                      ~~~~~~~~~

src/index.ts:32:28 - error TS2532: Object is possibly 'undefined'.

32         const prevRating = previousValue.rating;
                              ~~~~~~~~~~~~~

src/index.ts:39:26 - error TS2532: Object is possibly 'undefined'.

39     const restaurantID = eventData.restaurantID;
                            ~~~~~~~~~

src/index.ts:44:27 - error TS2532: Object is possibly 'undefined'.

44        const difference = previousValue.rating - rating
                             ~~~~~~~~~~~~~

src/index.ts:61:21 - error TS2532: Object is possibly 'undefined'.

61   const oldRating = restaurantDoc.data().averageRating;
                       ~~~~~~~~~~~~~~~~~~~~

src/index.ts:62:25 - error TS2532: Object is possibly 'undefined'.

62   const oldNumReviews = restaurantDoc.data().reviewCount;
                           ~~~~~~~~~~~~~~~~~~~~

which suggested either a mistype on my end or a change in how typescript evaluates code.

This stackoverflow question helped me figure out what to do. Thus the new contents of my index.ts file are:

//  Copyright (c) 2018 Google Inc.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
type Firestore = admin.firestore.Firestore; 
const app = admin.initializeApp(); 

export const computeAverageReview = functions.firestore 
  .document('reviews/{reviewId}').onWrite((change, context) => { 
    const eventData = change.after!.data();
    const prev = change.before;
    const rating = eventData!.rating; 
    let previousValue 

    if (prev.exists) {
        previousValue = prev.data();
        const prevRating = previousValue?.rating;
        if (rating === prevRating) {
           console.log("not a new rating.");
           return null;
        }
    }

    const restaurantID = eventData!.restaurantID;

    const db = app.firestore()

    if (prev.exists) {
       const difference = previousValue?.rating - rating 
       return updateAverage(db, restaurantID, difference, true);
    } else {
        return updateAverage(db, restaurantID, rating, false);
    } 
});

async function updateAverage(db: Firestore, restaurantID: string, newRating: number, prev: boolean) { 
  const updateDB = db.collection('restaurants').doc(restaurantID);
  const restaurantDoc = await updateDB.get();

  if (!restaurantDoc.exists) {
     console.log("Document does not exist!");
     return null;
  }

  const oldRating = restaurantDoc?.data()?.averageRating;
  const oldNumReviews = restaurantDoc?.data()?.reviewCount;

  let newNumReviews = oldNumReviews+1;
  let newAvgRating = ((oldRating*oldNumReviews)+newRating)/newNumReviews;

  if (prev) {
     newNumReviews = oldNumReviews;
     newAvgRating = ((oldRating*oldNumReviews)-newRating)/oldNumReviews;
  }

  await updateDB.update({averageRating: newAvgRating, reviewCount: newNumReviews});
  console.log("average updated");
  return null;
}

/**
 * TODO(DEVELOPER): Write the updateRest Function here.
*/

/**
 *TODO(DEVELOPER): Add updateRestaurant helper function here.
*/

Let me know what you think. Thanks

PS: the force unwrapping of the values makes me nervous. Is this the recommended way to do this? I could leave things like this for now till I wrap up the workshop and then look further into Typescript BUT if you have any insights that would be greatly appreciated as it would speed up my learning. Thanks

morganchen12 commented 4 years ago

Thanks for investigating, looks like the Typescript in the codelab needs to be updated.

The unwrapping is not the best way to do this, because it creates a tight coupling between your server function and the client. For example, in the review update handler, this line:

const eventData = change.after!.data();

will break if you ever add a feature to delete reviews to the app, since after will be undefined. In a complex, long-lived, and frequently-updated app, you will inevitably have users who choose to remain on older versions instead of upgrading their apps, so it's good to not tightly couple your functions to an app version's implementation because that inflexibility will cost you in the future.

Functions makes this easier since deploying is pretty easy and the functions themselves are stateless. So you could just add the force-unwraps as they are now and then just change them when you want to update your app. In the case of a few force-unwraps, this is only viable because removing the unwraps and handling the error case is easy.

C2SO commented 4 years ago

I am getting this same error. I went through and updated my dependencies in my package.json, but that didn't work.

morganchen12 commented 4 years ago

@C2SO can you file a new issue with your compiler/linter error?

Vijay1126 commented 4 years ago

No solution to this yet?

mueslifante commented 4 years ago

same problem !!

kansson commented 4 years ago

Same problem, appeared out of nowhere.. Haven't changed a bit in the code.

darktravel commented 4 years ago

Same problem

ViMan21 commented 4 years ago

Try running "firebase init hosting" before the deploy command