feat: adding production environment config (#317)

* feat: adding production config files

* better handling prod and dev environments

* small fixes and changes regarding prod

* fixing domains

* feat: fixing config functions host

* feat: properly loading firebase options depending on the env

* adding final prod domain url

* fix: lint
This commit is contained in:
Erick
2023-01-12 11:23:20 -03:00
committed by GitHub
parent 5f85e547d8
commit b5a41dfe3b
17 changed files with 195 additions and 26 deletions

View File

@ -1,8 +1,16 @@
{
"projects": {
"default": "io-photobooth-dev"
"default": "io-photobooth-dev",
"production": "holobooth-prod"
},
"targets": {
"holobooth-prod": {
"hosting": {
"app_prod": [
"0cf34931-6ab3-8cd9-57b5-f38b5fa5ba1e"
]
}
},
"io-photobooth-dev": {
"hosting": {
"app_dev": [

View File

@ -16,7 +16,7 @@ jobs:
flutter-version: "3.6.0-0.1.pre"
channel: "beta"
- run: flutter packages get
- run: flutter build web --web-renderer canvaskit
- run: flutter build web --web-renderer canvaskit -t lib/main_dev.dart
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -0,0 +1,26 @@
name: deploy_app_production
on:
workflow_dispatch:
jobs:
deploy-dev:
runs-on: ubuntu-latest
name: Deploy App Production
steps:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
flutter-version: "3.6.0-0.1.pre"
channel: "beta"
- run: flutter packages get
- run: flutter build web --web-renderer canvaskit -t lib/main_prod.dart
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_PHOTOBOOTH_PRODUCTION }}"
projectId: holobooth-prod
target: app_prod
expires: 30d
channelId: live

View File

@ -14,7 +14,7 @@ jobs:
flutter-version: "3.6.0-0.1.pre"
channel: "beta"
- run: flutter packages get
- run: flutter build web --web-renderer canvaskit
- run: flutter build web --web-renderer canvaskit -t lib/main_dev.dart
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -22,7 +22,7 @@ A Photo Booth built with [Flutter][flutter_link] and [Firebase][firebase_link] f
To run the desired project either use the launch configuration in VSCode/Android Studio or use the following commands:
```sh
$ flutter run -d chrome
$ flutter run -d chrome -t lib/main_dev.dart
```
_\*I/O Photo Booth works on Web._

View File

@ -1,7 +1,8 @@
include: package:very_good_analysis/analysis_options.3.1.0.yaml
analyzer:
exclude:
- lib/firebase_options.dart
- lib/firebase_options_dev.dart
- lib/firebase_options_prod.dart
- lib/**/*.gen.dart
linter:
rules:

View File

@ -99,6 +99,56 @@
}
],
"predeploy": []
},
{
"target": "app_prod",
"public": "build/web",
"cleanUrls": true,
"trailingSlash": false,
"ignore": [
".firebase",
"firebase.json",
"functions/node_modules",
"functions/src",
"__/**"
],
"rewrites": [
{ "source": "/share/**", "function": "shareImage" },
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
}
]
},
{
"source": "**/*.@(jpg|jpeg|gif|png)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=3600"
}
]
},
{
"source": "**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
}
],
"predeploy": []
}
],
"functions": {

View File

@ -2,11 +2,11 @@ export const ENV = process.env.NODE_ENV;
export const UPLOAD_PATH = 'uploads';
export const SHARE_PATH = 'share';
export const ALLOWED_HOSTS = [
'localhost:5001',
'io-photobooth-dev.web.app',
'io-photo-booth.web.app',
'us-central1-io-photobooth-dev.cloudfunctions.net',
'us-central1-io-photo-booth.cloudfunctions.net',
'photobooth.flutter.dev',
'convert-it4sycsdja-uc.a.run.app',
'http://localhost:5001',
'https://io-photobooth-dev.web.app',
'https://io-photo-booth.web.app',
'https://photobooth.flutter.dev',
'https://holobooth-prod.web.app',
'https://0cf34931-6ab3-8cd9-57b5-f38b5fa5ba1e.web.app',
'https://holobooth.flutter.dev',
];

View File

@ -205,7 +205,7 @@ jest.mock('firebase-admin', () => {
describe('convert', () => {
it('returns response with status 200 on success', async () => {
const mockRequest = mockDeep<functions.https.Request>();
mockRequest.get.mockReturnValue('localhost:5001');
mockRequest.get.mockReturnValue('http://localhost:5001');
mockRequest.protocol = 'https';
setUpBusboy('finish', 'end');
setUpFfmpeg('end');
@ -228,7 +228,7 @@ describe('convert', () => {
it('returns status 500 on error', async () => {
const mockRequest = mockDeep<functions.https.Request>();
mockRequest.get.mockReturnValue('localhost:5001');
mockRequest.get.mockReturnValue('http://localhost:5001');
mockRequest.protocol = 'https';
setUpBusboy('error', 'error');
@ -254,7 +254,7 @@ describe('convertImages', () => {
it('returns response with status 200 and file url on success', async () => {
const mockRequest = mockDeep<functions.https.Request>();
mockRequest.get.mockReturnValue('localhost:5001');
mockRequest.get.mockReturnValue('http://localhost:5001');
mockRequest.protocol = 'https';
setUpBusboy('finish', 'end');

View File

@ -51,13 +51,11 @@ export async function convertImages(
let tempDir: string | null = null;
try {
const host = req.get('host') ?? '';
const baseUrl = `${req.protocol}://${host}`;
const host = req.get('origin') ?? '';
if (!ALLOWED_HOSTS.includes(host)) {
functions.logger.log('Bad host', {
host,
baseUrl,
});
throw new Error('Bad host');
}

View File

@ -24,7 +24,7 @@ describe('Share API', () => {
path: '',
protocol: 'http',
get(_: string) {
return 'localhost:5001';
return 'http://localhost:5001';
},
} as functions.https.Request;

View File

@ -12,11 +12,13 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:io_photobooth/app/app.dart';
import 'package:io_photobooth/app/app_bloc_observer.dart';
import 'package:io_photobooth/firebase_options.dart';
import 'package:io_photobooth/landing/loading_indicator_io.dart'
if (dart.library.html) 'package:io_photobooth/landing/loading_indicator_web.dart';
Future<void> main() async {
Future<void> bootstrap({
required String convertUrl,
required FirebaseOptions firebaseOptions,
}) async {
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = AppBlocObserver();
FlutterError.onError = (details) {
@ -25,7 +27,7 @@ Future<void> main() async {
};
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
options: firebaseOptions,
);
final authenticationRepository = AuthenticationRepository(
@ -35,7 +37,7 @@ Future<void> main() async {
final avatarDetectorRepository = AvatarDetectorRepository();
final convertRepository = ConvertRepository(
url: 'https://convert-it4sycsdja-uc.a.run.app',
url: convertUrl,
);
runZonedGuarded(

View File

@ -0,0 +1,64 @@
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for android - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.iOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for ios - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyAJJhkSV4Mn2Yk4XhGc2Keitfy-iGRTXfQ',
appId: '1:2414555761:web:e13eb13e7dfd4b277561d0',
messagingSenderId: '2414555761',
projectId: 'holobooth-prod',
authDomain: 'holobooth-prod.firebaseapp.com',
storageBucket: 'holobooth-prod.appspot.com',
measurementId: 'G-KWF3BR55Z5',
);
}

10
lib/main_dev.dart Normal file
View File

@ -0,0 +1,10 @@
import 'package:io_photobooth/bootstrap.dart';
import 'package:io_photobooth/firebase_options_dev.dart';
Future<void> main() async {
const convertUrl = 'https://convert-it4sycsdja-uc.a.run.app';
await bootstrap(
convertUrl: convertUrl,
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
);
}

10
lib/main_prod.dart Normal file
View File

@ -0,0 +1,10 @@
import 'package:io_photobooth/bootstrap.dart';
import 'package:io_photobooth/firebase_options_prod.dart';
Future<void> main() async {
const convertUrl = 'https://convert-fge4q4vwia-uc.a.run.app';
await bootstrap(
convertUrl: convertUrl,
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
);
}

View File

@ -1,9 +1,9 @@
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{folder}/{imageId} {
allow read: if imageId.matches(".*\\.png") || imageId.matches(".*\\.jpg");
allow write: if false;
match /{allPaths=**} {
allow create: if request.auth != null;
allow read: if true;
}
}
}