@dev-aces/fireway v2.0.1
Fireway
A schema migration tool for Firestore. TypeScript and CommonJS JavaScript languages are supported.
Usage
Create a migration file in the functions/migration (default directory).
Name the file in the format: v[semver]__[description].ts (or .js).
TypeScript example:
// ./migrations/v0.0.1__typescript_example.ts
import { IMigrationFunctionsArguments } from '@dev-aces/fireway';
export async function migrate({ firestore }: IMigrationFunctionsArguments) {
await firestore
.collection('my_table')
.doc('document_id')
.set({ name: 'Fireway' });
}JavaScript example:
// ./migrations/v0.0.1__javascript_example.js
module.exports.migrate = async ({ firestore }) => {
await firestore
.collection('my_table')
.doc('document_id')
.set({ name: 'Fireway' });
};Extended example
The library is using Modular SDK for app initialization. It is possible to use the app argument in migration scripts to initialize another Firebase service, for example, auth.
// ./migrations/v0.2.0__typescript_extended_example.ts
import { IMigrationFunctionsArguments } from '@dev-aces/fireway';
import { getAuth } from 'firebase-admin/auth';
import { FieldValue } from 'firebase-admin/firestore';
export async function migrate({
firestore,
app,
}: IMigrationFunctionsArguments) {
// Auth example
const firebaseAuth = getAuth(app);
const email = 'test-user@test.com';
// search user identity
const user = await firebaseAuth.getUserByEmail(email);
if (!user) {
await firebaseAuth.createUser({
email: email,
emailVerified: true,
disabled: false,
});
}
// FieldValue example
await firestore.collection('table').doc('123').ref.update({
obsoleteField: FieldValue.delete(),
date: FieldValue.serverTimestamp(),
});
}Install
Install NPM package to Firebase functions projects:
npm i @dev-aces/fireway
For TypeScript additionally:
Install
ts-node:npm i ts-nodeAdd
tsconfig.jsonto thefunctionsfolder. Define ats-nodeconfiguration block inside yourtsconfig.jsonfile:{ "ts-node": { "transpileOnly": true, "compilerOptions": { "module": "commonjs" } } }
Running locally
Most likely you'll want to test your migration scripts locally first before running them against Cloud instances.
Ensure that Firestore emulator is set up in
firebase.jsonfile.{ "emulators": { "firestore": { "port": 8080 } } }Start your local emulators with
firebase emulators:startRun migrations.
To connect to the local emulator
GCLOUD_PROJECTenvironment variable is required pointing to your projectId. Check.firebasercfile and the{ "projects": { "default": "[project-id]" }}settings. If it is not specified, any value can be provided, e.g. "local".
SpecifyFIRESTORE_EMULATOR_HOSTvariable pointing to your local emulator (default Firestore port is8080).For TypeScript:
GCLOUD_PROJECT=project-id FIRESTORE_EMULATOR_HOST=localhost:8080 fireway --require="ts-node/register" migrateFor JavaScript:
GCLOUD_PROJECT=project-id FIRESTORE_EMULATOR_HOST=localhost:8080 fireway migrate
Migration results
Migration results are stored in the fireway collection (can be changed) in Firestore in the format v[semver]__[description].
// fireway/v0.0.1__typescript_example
{
installed_rank: 3, // 0-based sequence
checksum: 'fdfe6a55a7c97a4346cb59871b4ce97c',
description: 'typescript_example',
execution_time: 1221,
installed_by: 'system_user_name',
installed_on: Timestamp(),
script: 'v0.0.1__typescript_example.ts',
type: 'ts',
version: '0.0.1',
success: true
}Re-running script
If script execution failed, the workflow will be stopped. Running migration again will start from the latest failed script.
Running in Cloud
Generate a Firebase Service Account JSON key by opening: Project Settings -> Service Accounts -> Generate new private key. Private key will have the admin role and contain your project settings.
Set up CI provider to use that key. For Github Actions, add a secret to the Github repository, e.g.
FIREBASE_SERVICE_ACCOUNT_JSON_DEV.In the Github workflow use
google-github-actions/auth@v1to load the credentialsjobs: build_and_deploy: runs-on: ubuntu-latest name: Dev workflow steps: - uses: actions/checkout@v3 - name: 'NPP install and build steps' run: | echo "your scripts" - name: 'Authenticate to Google Cloud' uses: 'google-github-actions/auth@v1' with: credentials_json: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_DEV }}' create_credentials_file: true cleanup_credentials: true - name: Deploy functions and run migrations run: | npm run migrate firebase deploy --only functionswhere
package.jsonscripts section has:"migrate": "fireway migrate --require=\"ts-node/register\""
Alternatively use GOOGLE_APPLICATION_CREDENTIALS environment variable as described in Firebase Admin Auth instructions.
CLI
Usage
$ fireway migrate [options]
Available Commands
migrate Migrates schema to the latest version
For more info, run any command with the `--help` flag
$ fireway migrate --help
Options
--path Path to migration files (default "./migrations")
--collection Firebase collection name for migration results (default "fireway")
--require Requires a module before executing, example with TypeScript compiler: fireway migrate --require="ts-node/register"
--dryRun Simulates changes
--logLevel Log level, options: debug, log, warn, error (default "log")
-v, --version Displays current version
-h, --help Displays this messageContributing
Fork the repository, make changes, ensure that project is tested:
$ npm install
$ npm setup
$ npm run build && npm run testHistory
Based on kevlened/fireway work, which was inspired by flyway
License
MIT