Skip to content

Commit a54b0d0

Browse files
support firebase deploy command
1 parent cf6b551 commit a54b0d0

File tree

2 files changed

+115
-13
lines changed

2 files changed

+115
-13
lines changed

bin/flutterflow_cli.dart

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,30 @@ void main(List<String> args) async {
4444
}
4545

4646
try {
47-
await exportCode(
48-
token: token,
49-
endpoint: endpoint,
50-
projectId: project,
51-
destinationPath: parsedArguments.command!['dest'],
52-
includeAssets: parsedArguments.command!['include-assets'],
53-
branchName: parsedArguments.command!['branch-name'],
54-
unzipToParentFolder: parsedArguments.command!['parent-folder'],
55-
fix: parsedArguments.command!['fix'],
56-
exportAsModule: parsedArguments.command!['as-module'],
57-
);
47+
switch (parsedArguments.command?.name) {
48+
case 'export-code':
49+
await exportCode(
50+
token: token,
51+
endpoint: endpoint,
52+
projectId: project,
53+
destinationPath: parsedArguments.command!['dest'],
54+
includeAssets: parsedArguments.command!['include-assets'],
55+
branchName: parsedArguments.command!['branch-name'],
56+
unzipToParentFolder: parsedArguments.command!['parent-folder'],
57+
fix: parsedArguments.command!['fix'],
58+
exportAsModule: parsedArguments.command!['as-module'],
59+
);
60+
break;
61+
case 'firebase-deploy':
62+
await firebaseDeploy(
63+
token: token,
64+
projectId: project,
65+
destinationPath: parsedArguments.command!['dest'],
66+
endpoint: endpoint,
67+
);
68+
break;
69+
default:
70+
}
5871
} catch (_) {
5972
exit(1);
6073
}
@@ -98,12 +111,18 @@ ArgResults _parseArgs(List<String> args) {
98111
defaultsTo: false,
99112
);
100113

114+
final firebaseDeployCommandParser = ArgParser()
115+
..addOption('project', abbr: 'p', help: 'Project id')
116+
..addOption('dest',
117+
abbr: 'd', help: 'Destination directory', defaultsTo: '.');
118+
101119
final parser = ArgParser()
102120
..addOption('endpoint', abbr: 'e', help: 'Endpoint', hide: true)
103121
..addOption('environment', help: 'Environment', hide: true)
104122
..addOption('token', abbr: 't', help: 'API Token')
105123
..addFlag('help', negatable: false, abbr: 'h', help: 'Help')
106-
..addCommand('export-code', exportCodeCommandParser);
124+
..addCommand('export-code', exportCodeCommandParser)
125+
..addCommand('firebase-deploy', firebaseDeployCommandParser);
107126

108127
late ArgResults parsed;
109128
try {

lib/src/flutterflow_api_client.dart

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,22 @@ Future<dynamic> _callExport({
150150
if (branchName != null) 'branch_name': branchName,
151151
'export_as_module': exportAsModule,
152152
});
153+
return await _callEndpoint(
154+
client: client,
155+
token: token,
156+
url: Uri.https(endpoint.host, '${endpoint.path}/exportCode'),
157+
body: body,
158+
);
159+
}
160+
161+
Future<dynamic> _callEndpoint({
162+
required final http.Client client,
163+
required String token,
164+
required Uri url,
165+
required String body,
166+
}) async {
153167
final response = await client.post(
154-
Uri.https(endpoint.host, '${endpoint.path}/exportCode'),
168+
url,
155169
body: body,
156170
headers: {
157171
'Content-Type': 'application/json',
@@ -265,3 +279,72 @@ Future _runFix({
265279
stderr.write('Error running "dart fix": $e\n');
266280
}
267281
}
282+
283+
Future firebaseDeploy({
284+
required String token,
285+
required String projectId,
286+
required String destinationPath,
287+
String endpoint = kDefaultEndpoint,
288+
}) async {
289+
final endpointUrl = Uri.parse(endpoint);
290+
final body = jsonEncode({
291+
'project': {
292+
'path': 'projects/$projectId',
293+
},
294+
'token': token,
295+
});
296+
final result = await _callEndpoint(
297+
client: http.Client(),
298+
token: token,
299+
url: Uri.https(
300+
endpointUrl.host, '${endpointUrl.path}/exportFirebaseDeployCode'),
301+
body: body,
302+
);
303+
304+
// Download actual code
305+
final projectZipBytes = base64Decode(result['firebase_zip']);
306+
final firebaseProjectId = result['firebase_project_id'];
307+
final projectFolder = ZipDecoder().decodeBytes(projectZipBytes);
308+
extractArchiveToCurrentDirectory(projectFolder, destinationPath);
309+
final firebaseDir = '$destinationPath/firebase';
310+
311+
// Install required modules for deployment.
312+
await Process.run(
313+
'npm',
314+
['install'],
315+
workingDirectory: '$firebaseDir/functions',
316+
runInShell: true,
317+
stdoutEncoding: utf8,
318+
stderrEncoding: utf8,
319+
);
320+
final directoriesResult = await Process.run(
321+
'ls',
322+
[],
323+
workingDirectory: firebaseDir,
324+
runInShell: true,
325+
stdoutEncoding: utf8,
326+
stderrEncoding: utf8,
327+
);
328+
329+
// This directory only exists if there were custom cloud functions.
330+
if (directoriesResult.stdout.contains('custom_cloud_functions')) {
331+
await Process.run(
332+
'npm',
333+
['install'],
334+
workingDirectory: '$firebaseDir/custom_cloud_functions',
335+
runInShell: true,
336+
stdoutEncoding: utf8,
337+
stderrEncoding: utf8,
338+
);
339+
}
340+
341+
final deployProcess = await Process.start(
342+
'firebase',
343+
['deploy', '--project', firebaseProjectId],
344+
workingDirectory: firebaseDir,
345+
runInShell: true,
346+
);
347+
// There may be a need for the user to interactively provide inputs.
348+
deployProcess.stdout.transform(utf8.decoder).forEach(print);
349+
deployProcess.stdin.addStream(stdin);
350+
}

0 commit comments

Comments
 (0)