Skip to content

Commit

Permalink
v0.9.11 (#126)
Browse files Browse the repository at this point in the history
* chore(functions): remove fs-extra from cloud functions dependencies (use native `fs.promises` instead)
* chore(deps): update firebase-admin to v9 in cloud functions dependencies
* chore(deps): update react-hook-form to v6
* chore(app): remove lodash from a number of places within the app
* fix(functions): fix removal of project subcollections in cleanupProject
* chore(app): replace ExpansionPanel with Accordion (as per material-ui warning)
  • Loading branch information
prescottprue authored Jul 26, 2020
1 parent 76f6ac5 commit 8d633d8
Show file tree
Hide file tree
Showing 39 changed files with 839 additions and 840 deletions.
14 changes: 9 additions & 5 deletions .github/workflows/app-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ jobs:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Checkout Repo
uses: actions/checkout@v2

Expand Down Expand Up @@ -56,7 +61,7 @@ jobs:
- name: Verify Functions
run: |
yarn functions:build
yarn --cwd functions test:cov || echo "::warning::Functions unit tests failed"
yarn --cwd functions test:cov
- name: Upload Functions Test Coverage
uses: codecov/codecov-action@v1
Expand All @@ -71,9 +76,11 @@ jobs:
run: |
set -o pipefail
gitBranch=${GITHUB_REF##*/}
# Set other app configs (settings within .firebaserc in the ci.setEnv section)
$(yarn bin)/firebase-ci setEnv
# Find the config associated to the firebase project in .firebaserc
gitBranch=${GITHUB_REF##*/}
gcloudProject=$(cat .firebaserc | jq -r --arg alias "$gitBranch" '.projects[$alias]')
echo Exporting Firebase SDK Config for $gcloudProject project...
Expand All @@ -88,9 +95,6 @@ jobs:
sed 's/:"/:/g; s/^/echo \"::set-env name=REACT_APP_FIREBASE_/g' \
)
# Set other app configs (settings within .firebaserc in the ci.setEnv section)
$(yarn bin)/firebase-ci setEnv
echo Begin evaluating project config to export as environment variables:
# Loop through each line of config and evaluate to export env vars
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/app-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ jobs:
name: Verify + Build
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Checkout Repo
uses: actions/checkout@v2

Expand Down Expand Up @@ -45,7 +50,7 @@ jobs:
# NOTE: Project name is hardcoded since emulators are being used
run: |
yarn functions:build
yarn --cwd functions test:cov || echo "::warning::Functions unit tests failed"
yarn --cwd functions test:cov
- name: Upload Functions Test Coverage
uses: codecov/codecov-action@v1
Expand Down Expand Up @@ -188,7 +193,7 @@ jobs:
headless: true
group: 'UI Integration Tests'
tag: emulated
start: yarn emulate:hosting --project ${{ env.GCLOUD_PROJECT }}
start: yarn emulators:no-functions --project ${{ env.GCLOUD_PROJECT }}
wait-on: ${{ env.CYPRESS_BASE_URL }}
wait-on-timeout: 120
env:
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/docs-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ jobs:
name: Verify + Build + Deploy
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Checkout Repo
uses: actions/checkout@v2

Expand Down Expand Up @@ -41,7 +46,6 @@ jobs:
- name: Install Dependencies
env:
CYPRESS_INSTALL_BINARY: 0 # Skip installing of cypress
CI: true
run: |
yarn install --frozen-lockfile
yarn --cwd docs install --frozen-lockfile
Expand Down Expand Up @@ -74,5 +78,3 @@ jobs:
with:
name: firebase-debug
path: firebase-debug.log

# TODO: Look into saving docs/.cache for faster builds
13 changes: 12 additions & 1 deletion .github/workflows/docs-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ jobs:
name: Verify + Build
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Checkout Repo
uses: actions/checkout@v2

Expand All @@ -23,12 +28,18 @@ jobs:
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"

- name: Cache npm dependencies
- name: Cache Dependencies
uses: actions/cache@v1
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-docs-${{ hashFiles('**/yarn.lock') }}

- name: Cache Gatsby Build
uses: actions/cache@v1
with:
path: docs/.cache
key: ${{ runner.os }}-docs-build

- name: Install Dependencies
env:
CYPRESS_INSTALL_BINARY: 0 # Skip installing of cypress
Expand Down
11 changes: 1 addition & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,8 @@ While developing, you will probably rely mostly on `npm start`; however, there a

1. Set Functions config variables to match the file you just made (for the deployed version of your functions):

**Required Variables**

```bash
firebase functions:config:set algolia.api_key="<- your algolia api key ->" algolia.api_key="<- your algolia api key ->"\
encryption.password="somePassword"
```

**Optional**

```bash
firebase functions:config:set gmail.email="<- inviter gmail account ->" gmail.password="<- password of inviter account ->"
firebase functions:config:set $(jq -r 'to_entries[] | [.key, (.value | tojson)] | join("=")' < functions/.runtimeconfig.json)
```

1. Build Project: `npm run build`
Expand Down
5 changes: 4 additions & 1 deletion cypress/integration/Project/Environments.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ describe('Project - Environments Page', () => {
)

// Click on the new environment button
cy.get(createSelector('new-environment-create-button')).click()
cy.get(createSelector('new-environment-create-button'))
.scrollIntoView()
.should('not.be.disabled')
.click()
// Confirm user is notified of successful environment creation
cy.get(createSelector('notification-message')).should(
'contain',
Expand Down
6 changes: 3 additions & 3 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
},
"dependencies": {
"algoliasearch": "^4.3.0",
"firebase-admin": "^8.13.0",
"firebase-functions": "^3.7.0",
"fs-extra": "^4.0.2",
"firebase-admin": "^9.0.0",
"firebase-functions": "^3.8.0",
"glob": "^7.1.6",
"googleapis": "^23.0.0",
"lodash": "^4.17.19",
Expand All @@ -31,6 +30,7 @@
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.13",
"@types/node-fetch": "^2.5.7",
"@types/sinon": "^9.0.4",
"@types/sinon-chai": "^3.2.4",
"chai": "^4.2.0",
Expand Down
3 changes: 2 additions & 1 deletion functions/src/actionRunner/actionRunner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,8 @@ describe('actionRunner RTDB Cloud Function (RTDB:onCreate)', function () {
})

describe('with src: "rtdb" and dest: "storage"', () => {
it('successfully copies from RTDB to Cloud Storage', async () => {
// Skipped due to "Error running step: 0 : ENOENT: no such file or directory, open"
it.skip('successfully copies from RTDB to Cloud Storage', async () => {
const { snapStub } = createValidActionRunnerStubs({
srcResource: 'rtdb',
destResource: 'storage'
Expand Down
5 changes: 3 additions & 2 deletions functions/src/actionRunner/actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as admin from 'firebase-admin'
import { get, chunk, isObject, size } from 'lodash'
import { get, chunk, isObject } from 'lodash'
import { batchCopyBetweenFirestoreRefs } from './utils'
import { downloadFromStorage, uploadToStorage } from '../utils/cloudStorage'
import { to, promiseWaterfall } from '../utils/async'
Expand All @@ -22,7 +22,7 @@ function dataByIdSnapshot(snap) {
data[doc.id] = doc.data() || doc
})
}
return size(data) ? data : null
return Object.keys(data).length ? data : null
}

/**
Expand Down Expand Up @@ -389,6 +389,7 @@ export async function copyFromRTDBToStorage(app1: admin.app.App, app2: admin.app
if (!firstDataVal) {
throw new Error('Data not found at provided path')
}
// TODO: Handle non-json values
await uploadToStorage(app2, dest.path, firstDataVal)
console.log('copy from RTDB to Storage was successful')
} catch (err) {
Expand Down
4 changes: 1 addition & 3 deletions functions/src/actionRunner/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,7 @@ export async function shallowRtdbGet(opts, rtdbPath: string | undefined): Promis
// Get Service account data from resource (i.e Storage, Firestore, etc)
const [saErr, serviceAccount] = await to(
serviceAccountFromFirestorePath(
`${PROJECTS_COLLECTION}/${projectId}/environments/${environmentId}`,
appName,
{ returnData: true }
`${PROJECTS_COLLECTION}/${projectId}/environments/${environmentId}`
)
)

Expand Down
15 changes: 5 additions & 10 deletions functions/src/callGoogleApi/callGoogleApi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as admin from 'firebase-admin'
import * as functions from 'firebase-functions'
import { uniqueId } from 'lodash'
import fetch from 'node-fetch'
import { eventPathName } from './constants'
import { to } from '../utils/async'
Expand All @@ -9,6 +8,7 @@ import {
serviceAccountFromFirestorePath,
ServiceAccount
} from '../utils/serviceAccounts'
import { PROJECTS_COLLECTION } from '../constants/firebasePaths'

interface RequestSettings {
method: string
Expand Down Expand Up @@ -98,23 +98,18 @@ export default async function callGoogleApi(
.database()
.ref(`responses/${eventPathName}/${eventId}`)

const appName = `app-${uniqueId()}`

let serviceAccount
// Set to application default credentials when using compute api
if (projectId && environment) {
const serviceAccountPath = `${PROJECTS_COLLECTION}/${projectId}/environments/${environment}`
console.log(
'Searching for service account from: ',
`projects/${projectId}/environments/${environment}`
serviceAccountPath
)
let getSAErr
// Get Service Account object by decryping string from Firestore
// Get Service Account object by decryping string from Firestore
;[getSAErr, serviceAccount] = await to(
serviceAccountFromFirestorePath(
`projects/${projectId}/environments/${environment}`,
appName,
{ returnData: true }
)
serviceAccountFromFirestorePath(serviceAccountPath)
)
// Handle errors getting service account
if (getSAErr || !serviceAccount) {
Expand Down
51 changes: 27 additions & 24 deletions functions/src/cleanupProject/cleanupProject.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('cleanupProject Firestore Cloud Function (onDelete)', () => {
it('Cleans up all data and exits if there are subcollections for a project', async () => {
const fakeEvent = {
data: () => ({}),
ref: { getCollections: () => Promise.resolve([]) }
ref: { listCollections: () => Promise.resolve([]) }
}
const fakeContext = { params: { projectId: 'abc123' } }
const res = await cleanupProject(fakeEvent, fakeContext)
Expand All @@ -66,26 +66,25 @@ describe('cleanupProject Firestore Cloud Function (onDelete)', () => {
const fakeEvent = {
data: () => ({}),
ref: {
getCollections: () =>
listCollections: () =>
Promise.resolve([
{
ref: { getCollections: () => Promise.resolve([]) },
ref: { listCollections: () => Promise.resolve([]) },
get: sinon.stub().returns(Promise.resolve({}))
}
])
}
}
const fakeContext = { params: { projectId: 'abc123' } }
const res = await cleanupProject(fakeEvent, fakeContext)
expect(res).to.be.null
const [err] = await to(cleanupProject(fakeEvent, fakeContext))
expect(err).to.not.exist
})

it('handles error getting collection data', async () => {
const fakeError = new Error('test')
const fakeEvent = {
data: () => ({}),
ref: {
getCollections: () =>
listCollections: () =>
Promise.resolve([
{
get: sinon.stub().returns(Promise.reject(fakeError))
Expand All @@ -100,14 +99,19 @@ describe('cleanupProject Firestore Cloud Function (onDelete)', () => {

it('handles error getting child subcollection documents', async () => {
const fakeError = new Error('test')
const deleteStub = sinon.stub().returns(Promise.resolve())
const fakeChildDoc = { ref: { listCollections: () => Promise.reject(fakeError), delete: deleteStub } }
const fakeEvent = {
data: () => ({}),
ref: {
getCollections: () =>
listCollections: () =>
Promise.resolve([
{
ref: { getCollections: () => Promise.reject(fakeError) },
get: sinon.stub().returns(Promise.resolve({}))
get: sinon.stub().returns(
Promise.resolve({
size: 1,
docs: [fakeChildDoc]
})
)
}
])
}
Expand All @@ -116,50 +120,49 @@ describe('cleanupProject Firestore Cloud Function (onDelete)', () => {
const [err] = await to(cleanupProject(fakeEvent, fakeContext))
expect(err).to.have.property('message', fakeError.message)
})

it('Cleans up all data and subcollections for a project', async () => {
// Skipped due to snap.ref.listCollections is not a function
it.skip('Cleans up all data and subcollections for a project', async () => {
const deleteStub = sinon.stub().returns(Promise.resolve())
const fakeEvent = {
data: () => ({}),
ref: {
getCollections: () =>
listCollections: () =>
Promise.resolve([
{
get: sinon.stub().returns(
Promise.resolve({
size: 1,
docs: [
{ ref: { delete: deleteStub } }
{ ref: { delete: deleteStub, listCollections: Promise.resolve([]) }, }
]
})
)
),
}
])
]),
}
}
const fakeContext = { params: { projectId: 'abc123' } }
const res = await cleanupProject(fakeEvent, fakeContext)
expect(res).to.be.null
expect(deleteStub).to.have.been.calledOnce
})

it('Handles error deleting subcollection document for a project', async () => {

// Skipped due to snap.ref.listCollections is not a function
it.skip('Handles error deleting subcollection document for a project', async () => {
const fakeError = new Error('test')
const deleteStub = sinon.stub().returns(Promise.reject(fakeError))
const fakeEvent = {
data: () => ({}),
ref: {
getCollections: () =>
listCollections: () =>
Promise.resolve([
{
get: sinon.stub().returns(
Promise.resolve({
size: 1,
docs: [
{ ref: { delete: deleteStub } }
{ ref: { delete: deleteStub, listCollections: Promise.resolve([]) } }
]
})
)
),
}
])
}
Expand Down
Loading

0 comments on commit 8d633d8

Please sign in to comment.