From 1dbdaaeaed16ff3fe1bcb5b894fce80acd216fca Mon Sep 17 00:00:00 2001 From: Nils Reichardt Date: Sun, 3 Mar 2024 21:22:42 +0100 Subject: [PATCH] Add `sz deploy website` command to Sharezone Repo CLI (#1356) Closes #1348 --- .github/workflows/website_cd.yml | 20 +-- .../commands/src/deploy_website_command.dart | 135 ++++++++++++++++++ tools/sz_repo_cli/lib/src/main.dart | 4 +- 3 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 tools/sz_repo_cli/lib/src/commands/src/deploy_website_command.dart diff --git a/.github/workflows/website_cd.yml b/.github/workflows/website_cd.yml index b837e54b9..742ef5687 100644 --- a/.github/workflows/website_cd.yml +++ b/.github/workflows/website_cd.yml @@ -91,13 +91,15 @@ jobs: flutter pub global activate --source path "$CI_CD_DART_SCRIPTS_PACKAGE_PATH" echo $(pwd)/bin >> $GITHUB_PATH - - name: Build - run: sz build website --flavor ${{ matrix.environment.flavor }} + - name: Install Firebase CLI + run: npm i -g firebase-tools@11.24.1 - - uses: FirebaseExtended/action-hosting-deploy@v0 - with: - repoToken: "${{ secrets.GITHUB_TOKEN }}" - firebaseServiceAccount: "${{ secrets[matrix.environment.serviceAccountSecret] }}" - channelId: live - entryPoint: "./website" - projectId: ${{ matrix.environment.projectId }} + - name: Build and deploy website + env: + FIREBASE_HOSTING_KEY: ${{ secrets[matrix.environment.serviceAccountSecret] }} + run: | + echo $FIREBASE_HOSTING_KEY > firebase-hosting-key.json + export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/firebase-hosting-key.json + sz deploy website \ + --message "Workflow $GITHUB_JOB, commit $GITHUB_SHA" \ + --flavor ${{ matrix.environment.flavor }} diff --git a/tools/sz_repo_cli/lib/src/commands/src/deploy_website_command.dart b/tools/sz_repo_cli/lib/src/commands/src/deploy_website_command.dart new file mode 100644 index 000000000..a544b6f9a --- /dev/null +++ b/tools/sz_repo_cli/lib/src/commands/src/deploy_website_command.dart @@ -0,0 +1,135 @@ +// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) +// Licensed under the EUPL-1.2-or-later. +// +// You may obtain a copy of the Licence at: +// https://joinup.ec.europa.eu/software/page/eupl +// +// SPDX-License-Identifier: EUPL-1.2 + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:process_runner/process_runner.dart'; +import 'package:sz_repo_cli/src/common/common.dart'; + +/// Maps the different flavors to the corresponding Firebase project ID. +final _flavorToProjectId = { + 'prod': 'sharezone-c2bd8', + 'dev': 'sharezone-debug', +}; + +/// The different flavors of the web app that support deployment. +final _webFlavors = [ + 'prod', + 'dev', +]; + +/// Deploy the Sharezone web app to one of the several deploy sites (e.g. alpha +/// or production). +/// +/// The command will automatically use the right firebase config as configured +/// inside [_stageToTarget]. +class DeployWebsiteCommand extends CommandBase { + DeployWebsiteCommand(super.context) { + argParser + ..addOption( + firebaseDeployMessageOptionName, + help: + '(Optional) The message given to "firebase deploy --only:hosting" via the "--message" flag. Will default to the current commit hash.', + ) + ..addOption( + flavorOptionName, + allowed: _webFlavors, + help: 'The flavor to build for.', + defaultsTo: 'prod', + ); + } + + static const firebaseDeployMessageOptionName = 'message'; + static const flavorOptionName = 'flavor'; + + @override + String get description => + 'Deploy the Sharezone website in the given environment'; + + @override + String get name => 'website'; + + @override + Future run() async { + // Its less work to just print everything right now instead of selectively + // print and add custom print statements for non-verbose output. + // One might add non-verbose output in the future but right now this is + // easier. + isVerbose = true; + + await _build(); + await _deploy(); + } + + Future _build() async { + final flavor = argResults![flavorOptionName] as String; + await processRunner.runCommand([ + 'fvm', + 'dart', + 'run', + 'sz_repo_cli', + 'build', + 'website', + '--flavor', + flavor, + ], workingDirectory: repo.sharezoneCiCdTool.location); + } + + Future _deploy() async { + final flavor = argResults![flavorOptionName] as String; + final firebaseProjectId = _flavorToProjectId[flavor]!; + + final deployMessage = await _getDeployMessage(); + + await processRunner.run( + [ + 'firebase', + 'deploy', + '--project', + firebaseProjectId, + '--message', + deployMessage, + ], + workingDirectory: repo.sharezoneWebsite.location, + ); + } + + Future _getDeployMessage() async { + final overriddenDeployMessage = _parseDeployMessage(argResults!); + + String? deployMessage; + if (overriddenDeployMessage == null) { + final currentCommit = await _getCurrentCommitHash(processRunner); + deployMessage = 'Commit: $currentCommit'; + } + + return deployMessage ?? overriddenDeployMessage!; + } + + String? _parseDeployMessage(ArgResults argResults) { + final overriddenDeployMessageOrNull = + argResults[firebaseDeployMessageOptionName] as String?; + return overriddenDeployMessageOrNull; + } + + Future _getCurrentCommitHash(ProcessRunner processRunner) async { + final res = await processRunner.run(['git', 'rev-parse', 'HEAD']); + if (res.stdout.isEmpty) { + stderr.writeln( + 'Could not receive the current commit hash: (${res.exitCode}) ${res.stderr}.'); + throw ToolExit(15); + } + final currentCommit = res.stdout; + if (isVerbose) { + stdout.writeln('Got current commit hash: $currentCommit'); + } + return currentCommit; + } +} diff --git a/tools/sz_repo_cli/lib/src/main.dart b/tools/sz_repo_cli/lib/src/main.dart index 7c18cd82e..75df01dc0 100644 --- a/tools/sz_repo_cli/lib/src/main.dart +++ b/tools/sz_repo_cli/lib/src/main.dart @@ -25,6 +25,7 @@ import 'package:sz_repo_cli/src/commands/src/check_license_headers_command.dart' import 'package:sz_repo_cli/src/commands/src/deploy_android_command.dart'; import 'package:sz_repo_cli/src/commands/src/deploy_ios_command.dart'; import 'package:sz_repo_cli/src/commands/src/deploy_macos_command.dart'; +import 'package:sz_repo_cli/src/commands/src/deploy_website_command.dart'; import 'package:sz_repo_cli/src/commands/src/format_command.dart'; import 'package:sz_repo_cli/src/commands/src/license_headers_command.dart'; @@ -67,7 +68,8 @@ Future main(List args) async { ..addSubcommand(DeployWebAppCommand(context)) ..addSubcommand(DeployIosCommand(context)) ..addSubcommand(DeployMacOsCommand(context)) - ..addSubcommand(DeployAndroidCommand(context))) + ..addSubcommand(DeployAndroidCommand(context)) + ..addSubcommand(DeployWebsiteCommand(context))) ..addCommand(BuildCommand() ..addSubcommand(BuildAndroidCommand(context)) ..addSubcommand(BuildMacOsCommand(context))