diff --git a/.gitignore b/.gitignore index 5c1068399458..a633c32f6550 100644 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,7 @@ website/www/yarn-error.log playground/frontend/playground_components/pubspec.lock playground/frontend/playground_components/test/tools/extract_symbols_java/dependencies playground/frontend/playground_components_dev/pubspec.lock +learning/tour-of-beam/frontend/pubspec.lock # Ignore Beam Playground Terraform **/.terraform diff --git a/learning/tour-of-beam/frontend/firebase.json b/learning/tour-of-beam/frontend/firebase.json new file mode 100644 index 000000000000..66037326c171 --- /dev/null +++ b/learning/tour-of-beam/frontend/firebase.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "public": "build/web", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/learning/tour-of-beam/frontend/lib/models/unit_content.g.dart b/learning/tour-of-beam/frontend/lib/models/unit_content.g.dart index 8c3db0eb223b..46856ba3d45c 100644 --- a/learning/tour-of-beam/frontend/lib/models/unit_content.g.dart +++ b/learning/tour-of-beam/frontend/lib/models/unit_content.g.dart @@ -16,4 +16,4 @@ UnitContentModel _$UnitContentModelFromJson(Map json) => hints: (json['hints'] as List?)?.map((e) => e as String).toList() ?? [], - ); + ); \ No newline at end of file diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 19646be75431..b49a1310be09 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -213,12 +213,12 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { return playgroundController; } - @override - void dispose() { +@override + Future dispose() async { _unitContentCache.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); _appNotifier.removeListener(_onAppNotifierChanged); _authNotifier.removeListener(_onUnitProgressChanged); - super.dispose(); - } + await super.dispose(); + } } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index 8986de435290..5a1840bcddb1 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -37,7 +37,7 @@ class CloudFunctionsTobClient extends TobClient { Future getSdks() async { final json = await http.get( Uri.parse( - '$cloudFunctionsBaseUrl/getSdkList', + '${cloudFunctionsBaseUrl}getSdkList', ), ); @@ -49,7 +49,7 @@ class CloudFunctionsTobClient extends TobClient { Future getContentTree(String sdkId) async { final json = await http.get( Uri.parse( - '$cloudFunctionsBaseUrl/getContentTree?sdk=$sdkId', + '${cloudFunctionsBaseUrl}getContentTree?sdk=$sdkId', ), ); @@ -62,7 +62,7 @@ class CloudFunctionsTobClient extends TobClient { Future getUnitContent(String sdkId, String unitId) async { final json = await http.get( Uri.parse( - '$cloudFunctionsBaseUrl/getUnitContent?sdk=$sdkId&id=$unitId', + '${cloudFunctionsBaseUrl}getUnitContent?sdk=$sdkId&id=$unitId', ), ); @@ -78,7 +78,7 @@ class CloudFunctionsTobClient extends TobClient { } final json = await http.get( Uri.parse( - '$cloudFunctionsBaseUrl/getUserProgress?sdk=$sdkId', + '${cloudFunctionsBaseUrl}getUserProgress?sdk=$sdkId', ), headers: { HttpHeaders.authorizationHeader: 'Bearer $token', @@ -94,7 +94,7 @@ class CloudFunctionsTobClient extends TobClient { final token = await GetIt.instance.get().getToken(); await http.post( Uri.parse( - '$cloudFunctionsBaseUrl/postUnitComplete?sdk=$sdkId&id=$id', + '${cloudFunctionsBaseUrl}postUnitComplete?sdk=$sdkId&id=$id', ), headers: { HttpHeaders.authorizationHeader: 'Bearer $token', diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index b2e11cd2ab00..3c45d15f7961 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -5,322 +5,368 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: "8745ddb5f27423c6ba4cc3b182688407239fe38f73ef93a0db0a3497ddf4c2e6" + url: "https://pub.dev" source: hosted version: "46.0.0" _flutterfire_internals: dependency: transitive description: name: _flutterfire_internals - url: "https://pub.dartlang.org" + sha256: "3ff770dfff04a67b0863dff205a0936784de1b87a5e99b11c693fc10e66a9ce3" + url: "https://pub.dev" source: hosted version: "1.0.12" aligned_dialog: dependency: transitive description: name: aligned_dialog - url: "https://pub.dartlang.org" + sha256: c6ce4f82a5ab35dde2c48caa436eab4da9d6a4238802f67312c878394caf055d + url: "https://pub.dev" source: hosted version: "0.0.6" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "2c93c461a00a27dad2849137304d32b3c6b79c75b1d10ec9547ce329de329524" + url: "https://pub.dev" source: hosted version: "4.6.0" app_state: dependency: "direct main" description: name: app_state - url: "https://pub.dartlang.org" + sha256: "5019d60ed6381f571ed826b9581259ee47494082a59eb683838ff647d00a1090" + url: "https://pub.dev" source: hosted version: "0.8.4" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb" + url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.2" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + url: "https://pub.dev" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" autotrie: dependency: transitive description: name: autotrie - url: "https://pub.dartlang.org" + sha256: "55da6faefb53cfcb0abb2f2ca8636123fb40e35286bb57440d2cf467568188f8" + url: "https://pub.dev" source: hosted version: "2.0.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: "29a03af98de60b4eb9136acd56608a54e989f6da238a80af739415b05589d6df" + url: "https://pub.dev" source: hosted version: "2.3.0" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: "5b7355c14258f5e7df24bad1566f7b991de3e54aeacfb94e1a65e5233d9739c1" + url: "https://pub.dev" source: hosted version: "1.1.0" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + url: "https://pub.dev" source: hosted version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: "9aae031a54ab0beebc30a888c93e900d15ae2fd8883d031dbfbd5ebdb57f5a4c" + url: "https://pub.dev" source: hosted version: "2.0.9" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: "56942f8114731d1e79942cd981cfef29501937ff1bccf4dbdce0273f31f13640" + url: "https://pub.dev" source: hosted version: "2.2.0" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: f4d6244cc071ba842c296cb1c4ee1b31596b9f924300647ac7a1445493471a3f + url: "https://pub.dev" source: hosted version: "7.2.3" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: d7a9cd57c215bdf8d502772447aa6b52a8ab3f956d25d5fdea6ef1df2d2dad60 + url: "https://pub.dev" source: hosted version: "8.4.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + url: "https://pub.dev" source: hosted version: "2.0.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "43743b95913fd28b95184eb1bed7e4bd85b802b8fad0a52522702dbeda4ee3d5" + url: "https://pub.dev" source: hosted version: "4.2.0" collection: dependency: "direct main" description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" color: dependency: transitive description: name: color - url: "https://pub.dartlang.org" + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" source: hosted version: "3.0.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "196284f26f69444b7f5c50692b55ec25da86d9e500451dc09333bf2e3ad69259" + url: "https://pub.dev" source: hosted version: "3.0.2" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" csv: dependency: transitive description: name: csv - url: "https://pub.dartlang.org" + sha256: "18aef53ab72181a0b5384562d18c8cbd57e941e24cb8e54eb41409d3d8abdc6d" + url: "https://pub.dev" source: hosted version: "5.0.1" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "8aff82f9b26fd868992e5430335a9d773bfef01e1d852d7ba71bf4c5d9349351" + url: "https://pub.dev" source: hosted version: "2.2.3" dartx: dependency: transitive description: name: dartx - url: "https://pub.dartlang.org" + sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871" + url: "https://pub.dev" source: hosted version: "1.1.0" easy_localization: dependency: "direct main" description: name: easy_localization - url: "https://pub.dartlang.org" + sha256: "6a2e99fa0bfe5765bf4c6ca9b137d5de2c75593007178c5e4cd2ae985f870080" + url: "https://pub.dev" source: hosted version: "3.0.1" easy_localization_ext: dependency: "direct main" description: name: easy_localization_ext - url: "https://pub.dartlang.org" + sha256: "7a5ff2595436141f2e4873b69576ff33034fe23fef252fa592b2575be3fba33a" + url: "https://pub.dev" source: hosted version: "0.1.1" easy_localization_loader: dependency: "direct main" description: name: easy_localization_loader - url: "https://pub.dartlang.org" + sha256: f915f5cb6ec6eba8b87c023870c129a816f62ed47004a4fdfd8fc830f23e475e + url: "https://pub.dev" source: hosted version: "1.0.0" easy_logger: dependency: transitive description: name: easy_logger - url: "https://pub.dartlang.org" + sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 + url: "https://pub.dev" source: hosted version: "0.0.2" enum_map: dependency: transitive description: name: enum_map - url: "https://pub.dartlang.org" + sha256: "0dfe18306d2e9b0e9d381f5e11aac4c8255d5f5eddc68b0ab037f7d00aa36126" + url: "https://pub.dev" source: hosted version: "0.2.1" equatable: dependency: "direct main" description: name: equatable - url: "https://pub.dartlang.org" + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" source: hosted version: "2.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" source: hosted version: "2.0.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.4" firebase_auth: dependency: "direct main" description: name: firebase_auth - url: "https://pub.dartlang.org" + sha256: "721b90fe1a0966add31b47a490672954ac4fe45cfe721fd8a11ffbf4c166f611" + url: "https://pub.dev" source: hosted version: "4.1.4" firebase_auth_platform_interface: dependency: "direct main" description: name: firebase_auth_platform_interface - url: "https://pub.dartlang.org" + sha256: "325d934e21826b3e7030f5018ef61927e2083b4c4fb25218ddef6ffc0012b717" + url: "https://pub.dev" source: hosted version: "6.11.7" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - url: "https://pub.dartlang.org" + sha256: "1a7fe4aafed9b29229aa1de6910e0631be94633b4a235e739cc2830a0f110361" + url: "https://pub.dev" source: hosted version: "5.1.3" firebase_core: dependency: "direct main" description: name: firebase_core - url: "https://pub.dartlang.org" + sha256: c129209ba55f3d4272c89fb4a4994c15bea77fb6de63a82d45fb6bc5c94e4355 + url: "https://pub.dev" source: hosted version: "2.4.1" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - url: "https://pub.dartlang.org" + sha256: "5fab93f5b354648efa62e7cc829c90efb68c8796eecf87e0888cae2d5f3accd4" + url: "https://pub.dev" source: hosted version: "4.5.2" firebase_core_web: dependency: transitive description: name: firebase_core_web - url: "https://pub.dartlang.org" + sha256: "18b35ce111b0a4266abf723c825bcf9d4e2519d13638cc7f06f2a8dd960c75bc" + url: "https://pub.dev" source: hosted version: "2.1.0" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + url: "https://pub.dev" source: hosted version: "1.0.1" flutter: @@ -332,7 +378,8 @@ packages: dependency: transitive description: name: flutter_code_editor - url: "https://pub.dartlang.org" + sha256: a2133b2da3c6ac29f6e66adfdcde8914d1a98fbc1ca80a2ee9400bc670b1f1f7 + url: "https://pub.dev" source: hosted version: "0.2.5" flutter_driver: @@ -344,28 +391,32 @@ packages: dependency: transitive description: name: flutter_gen_core - url: "https://pub.dartlang.org" + sha256: f22863d36b4775d153c5b23f86091115b2f12c4020f6fefb5823bafe59940293 + url: "https://pub.dev" source: hosted version: "4.3.0" flutter_gen_runner: dependency: "direct dev" description: name: flutter_gen_runner - url: "https://pub.dartlang.org" + sha256: "16adc8aa4f7bab75630e6cab209b9b1db8ac8ac5db3f586e41d70a2867c575d6" + url: "https://pub.dev" source: hosted version: "4.3.0" flutter_highlight: dependency: transitive description: name: flutter_highlight - url: "https://pub.dartlang.org" + sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" + url: "https://pub.dev" source: hosted version: "0.7.0" flutter_issue_108697_workaround: dependency: transitive description: name: flutter_issue_108697_workaround - url: "https://pub.dartlang.org" + sha256: "71401a9196e1e8ed7a6463b8ab8ea6bf8d8cc719783c4be309553d64d8c353ec" + url: "https://pub.dev" source: hosted version: "0.1.2" flutter_localizations: @@ -377,14 +428,16 @@ packages: dependency: "direct main" description: name: flutter_markdown - url: "https://pub.dartlang.org" + sha256: "1e8cce3070d412de866905569e05fdd5407b78057be1cb9b09e6c5ae1579646c" + url: "https://pub.dev" source: hosted version: "0.6.12" flutter_svg: dependency: "direct main" description: name: flutter_svg - url: "https://pub.dartlang.org" + sha256: c9bb2757b8a0bbf8e45f4069a90d2b9dbafc80b1a5e28d43e29088be533e6df4 + url: "https://pub.dev" source: hosted version: "1.0.3" flutter_test: @@ -401,14 +454,16 @@ packages: dependency: transitive description: name: fluttertoast - url: "https://pub.dartlang.org" + sha256: "7a738eddad04c7b27a1ecfecd12e8ecd4b188cdd2d91c252a02a4aba65838c9d" + url: "https://pub.dev" source: hosted version: "8.1.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b" + url: "https://pub.dev" source: hosted version: "2.1.3" fuchsia_remote_debug_protocol: @@ -420,119 +475,136 @@ packages: dependency: "direct main" description: name: get_it - url: "https://pub.dartlang.org" + sha256: "290fde3a86072e4b37dbb03c07bec6126f0ecc28dad403c12ffe2e5a2d751ab7" + url: "https://pub.dev" source: hosted version: "7.2.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: c51b4fdfee4d281f49b8c957f1add91b815473597f76bcf07377987f66a55729 + url: "https://pub.dev" source: hosted version: "2.1.0" google_fonts: dependency: "direct main" description: name: google_fonts - url: "https://pub.dartlang.org" + sha256: "8f099045e2f2a30e4d4d0a35f40c6bc941a8f2ca0e10ad9d214ee9edd3f37483" + url: "https://pub.dev" source: hosted version: "3.0.1" google_sign_in: dependency: "direct main" description: name: google_sign_in - url: "https://pub.dartlang.org" + sha256: d3e31052ce068d0fe2eb9975ee4409266a044592cf67737ec230be07343c6bdf + url: "https://pub.dev" source: hosted version: "5.4.2" google_sign_in_android: dependency: transitive description: name: google_sign_in_android - url: "https://pub.dartlang.org" + sha256: "41187ee48f8f3f7588cb932a5ab3cc8c83f354d1d50c750f61b240efac1b33d2" + url: "https://pub.dev" source: hosted version: "6.1.4" google_sign_in_ios: dependency: transitive description: name: google_sign_in_ios - url: "https://pub.dartlang.org" + sha256: "1116aff5e87f89837b052a81abe6259be7c4dd418275786864d27b74cb2a4e70" + url: "https://pub.dev" source: hosted version: "5.5.1" google_sign_in_platform_interface: dependency: transitive description: name: google_sign_in_platform_interface - url: "https://pub.dartlang.org" + sha256: "61306213c76bb8170c3aa20017df296c0131c24d7f6c0cc7e2eeaeac34c9f457" + url: "https://pub.dev" source: hosted version: "2.3.0" google_sign_in_web: dependency: transitive description: name: google_sign_in_web - url: "https://pub.dartlang.org" + sha256: "5b35c221169a7b3e0fc15043ac09102ef542300ef92f2e1f05d5d8efde263af5" + url: "https://pub.dev" source: hosted version: "0.10.2" googleapis_auth: dependency: transitive description: name: googleapis_auth - url: "https://pub.dartlang.org" + sha256: "127b1bbd32170ab8312f503bd57f1d654d8e4039ddfbc63c027d3f7ade0eff74" + url: "https://pub.dev" source: hosted version: "1.3.1" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: ae0b3d956ff324c6f8671f08dcb2dbd71c99cdbf2aa3ca63a14190c47aa6679c + url: "https://pub.dev" source: hosted version: "2.1.0" grpc: dependency: transitive description: name: grpc - url: "https://pub.dartlang.org" + sha256: "3e8e04c6277059b66d67951143842097e52bbf3f2c6fca2e67d3607b48d5c3ab" + url: "https://pub.dev" source: hosted version: "3.0.2" highlight: dependency: transitive description: name: highlight - url: "https://pub.dartlang.org" + sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" + url: "https://pub.dev" source: hosted version: "0.7.0" hive: dependency: transitive description: name: hive - url: "https://pub.dartlang.org" + sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" + url: "https://pub.dev" source: hosted version: "2.2.3" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http2: dependency: transitive description: name: http2 - url: "https://pub.dartlang.org" + sha256: feb9fbe4790be90fef454eb930368c40ae56df598b3e9b9c10cc216d68f75720 + url: "https://pub.dev" source: hosted version: "2.0.0" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: db3060f22889f3d9d55f6a217565486737037eec3609f7f3eca4d0c67ee0d8a0 + url: "https://pub.dev" source: hosted version: "4.0.1" integration_test: @@ -544,196 +616,216 @@ packages: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" source: hosted version: "0.17.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" + url: "https://pub.dev" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" json_annotation: dependency: "direct main" description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: "3520fa844009431b5d4491a5a778603520cdc399ab3406332dcc50f93547258c" + url: "https://pub.dev" source: hosted version: "4.7.0" json_serializable: dependency: "direct dev" description: name: json_serializable - url: "https://pub.dartlang.org" + sha256: "581006a34721ff9b9cbc2ba6aab4c81ee9a9f345e9f046f9feef5732417cfe4b" + url: "https://pub.dev" source: hosted version: "6.4.1" keyed_collection_widgets: dependency: transitive description: name: keyed_collection_widgets - url: "https://pub.dartlang.org" + sha256: "9db2df4c4897c35fe167bdca82d307d81baa4161c3118da3f06ab4fd2d75291b" + url: "https://pub.dev" source: hosted version: "0.4.3" linked_scroll_controller: dependency: transitive description: name: linked_scroll_controller - url: "https://pub.dartlang.org" + sha256: e6020062bcf4ffc907ee7fd090fa971e65d8dfaac3c62baf601a3ced0b37986a + url: "https://pub.dev" source: hosted version: "0.2.0" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: "293ae2d49fd79d4c04944c3a26dfd313382d5f52e821ec57119230ae16031ad4" + url: "https://pub.dev" source: hosted version: "1.0.2" markdown: dependency: "direct main" description: name: markdown - url: "https://pub.dartlang.org" + sha256: c2b81e184067b41d0264d514f7cdaa2c02d38511e39d6521a1ccc238f6d7b3f2 + url: "https://pub.dev" source: hosted version: "6.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a + url: "https://pub.dev" source: hosted version: "1.0.2" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" - os_detect: - dependency: transitive - description: - name: os_detect - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" path_drawing: dependency: transitive description: name: path_drawing - url: "https://pub.dartlang.org" + sha256: a19347362f85a45aadf6bdfa3c04f18ff6676c445375eecd6251f9e09b9db551 + url: "https://pub.dev" source: hosted version: "1.0.0" path_parsing: dependency: transitive description: name: path_parsing - url: "https://pub.dartlang.org" + sha256: "9508ebdf1c3ac3a68ad5fb15edab8b026382999f18f77352349e56fbd74183ac" + url: "https://pub.dev" source: hosted version: "1.0.0" path_provider: dependency: transitive description: name: path_provider - url: "https://pub.dartlang.org" + sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd" + url: "https://pub.dev" source: hosted version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: "833c8bcb182b515cd872c113e29aaaffd29a1c720259dd2f65ab35ed5e0db748" + url: "https://pub.dev" source: hosted version: "2.0.17" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.dartlang.org" + sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8" + url: "https://pub.dev" source: hosted version: "2.0.11" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + url: "https://pub.dev" source: hosted version: "2.1.7" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8" + url: "https://pub.dev" source: hosted version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: "27dc7a224fcd07444cb5e0e60423ccacea3e13cf00fc5282ac2c918132da931d" + url: "https://pub.dev" source: hosted version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: "999d3dc2ac03ca3f8433018efa40b73558fa4f9759bf8383a217861d120c7d74" + url: "https://pub.dev" source: hosted version: "2.1.0" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71" + url: "https://pub.dev" source: hosted version: "5.0.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" playground_components: @@ -747,140 +839,160 @@ packages: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" source: hosted version: "4.2.4" protobuf: dependency: transitive description: name: protobuf - url: "https://pub.dartlang.org" + sha256: "01dd9bd0fa02548bf2ceee13545d4a0ec6046459d847b6b061d8a27237108a08" + url: "https://pub.dev" source: hosted version: "2.1.0" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + sha256: "8d7d4c2df46d6a6270a4e10404bfecb18a937e3e00f710c260d0a10415ce6b7b" + url: "https://pub.dev" source: hosted version: "6.0.3" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "816c1a640e952d213ddd223b3e7aafae08cd9f8e1f6864eed304cc13b0272b07" + url: "https://pub.dev" source: hosted version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + url: "https://pub.dev" source: hosted version: "1.2.1" quiver: dependency: transitive description: name: quiver - url: "https://pub.dartlang.org" + sha256: "93982981971e812c94d4a6fa3a57b89f9ec12b38b6380cd3c1370c3b01e4580e" + url: "https://pub.dev" source: hosted version: "3.1.0" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.dartlang.org" + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" source: hosted version: "0.27.7" scrollable_positioned_list: dependency: transitive description: name: scrollable_positioned_list - url: "https://pub.dartlang.org" + sha256: ca7fcaa743db712d4f7b1580526f494d0093c77a721a65705ee51fbeac7a2bd3 + url: "https://pub.dev" source: hosted version: "0.3.5" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + sha256: "76917b7d4b9526b2ba416808a7eb9fb2863c1a09cf63ec85f1453da240fa818a" + url: "https://pub.dev" source: hosted version: "2.0.15" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + sha256: "853801ce6ba7429ec4e923e37317f32a57c903de50b8c33ffcfbdb7e6f0dd39c" + url: "https://pub.dev" source: hosted version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios - url: "https://pub.dartlang.org" + sha256: "585a14cefec7da8c9c2fb8cd283a3bb726b4155c0952afe6a0caaa7b2272de34" + url: "https://pub.dev" source: hosted version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + sha256: "28aefc1261746e7bad3d09799496054beb84e8c4ffcdfed7734e17b4ada459a5" + url: "https://pub.dev" source: hosted version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos - url: "https://pub.dartlang.org" + sha256: fbb94bf296576f49be37a1496d5951796211a8db0aa22cc0d68c46440dad808c + url: "https://pub.dev" source: hosted version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + sha256: "992f0fdc46d0a3c0ac2e5859f2de0e577bbe51f78a77ee8f357cbe626a2ad32d" + url: "https://pub.dev" source: hosted version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + url: "https://pub.dev" source: hosted version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + sha256: "97f7ab9a7da96d9cf19581f5de520ceb529548498bd6b5e0ccd02d68a0d15eba" + url: "https://pub.dev" source: hosted version: "2.1.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: "8ec607599dd0a78931a5114cdac7d609b6dbbf479a38acc9a6dba024b2a30ea0" + url: "https://pub.dev" source: hosted version: "1.3.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: "6db16374bc3497d21aa0eebe674d3db9fdf82082aac0f04dc7b44e4af5b08afc" + url: "https://pub.dev" source: hosted version: "1.0.2" sky_engine: @@ -892,231 +1004,264 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + sha256: "85f8c7d6425dff95475db618404732f034c87fe23efe05478cea50520a2517a3" + url: "https://pub.dev" source: hosted version: "1.2.5" source_helper: dependency: transitive description: name: source_helper - url: "https://pub.dartlang.org" + sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" + url: "https://pub.dev" source: hosted version: "1.3.3" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: ed464977cb26a1f41537e177e190c67223dbd9f4f683489b6ab2e5d211ec564e + url: "https://pub.dev" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" sync_http: dependency: transitive description: name: sync_http - url: "https://pub.dartlang.org" + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" source: hosted version: "0.3.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" time: dependency: transitive description: name: time - url: "https://pub.dartlang.org" + sha256: "267028bb7b3e87bbfd66876c6389d7101e4b14eb94fe863d3e008e497ca07844" + url: "https://pub.dev" source: hosted version: "2.1.2" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: c386d07d7f5efc613479a7c4d9d64b03710b03cfaa7e8ad5f2bfb295a1f0dfad + url: "https://pub.dev" source: hosted version: "1.0.0" total_lints: dependency: "direct dev" description: name: total_lints - url: "https://pub.dartlang.org" + sha256: "8da9ee8d6a8e7c28e5e25bc6f35fb2102eaa7151044d7fabfa11c293ad8b4281" + url: "https://pub.dev" source: hosted version: "2.17.4" tuple: dependency: transitive description: name: tuple - url: "https://pub.dartlang.org" + sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + url: "https://pub.dev" source: hosted version: "2.0.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: "4f0d5f9bf7efba3da5a7ff03bd33cc898c84bac978c068e1c94483828e709592" + url: "https://pub.dev" source: hosted version: "6.1.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: "1ccd353c1bff66b49863527c02759f4d06b92744bd9777c96a00ca6a9e8e1d2f" + url: "https://pub.dev" source: hosted version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: "6ba7dddee26c9fae27c9203c424631109d73c8fa26cfa7bc3e35e751cb87f62e" + url: "https://pub.dev" source: hosted version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: "360fa359ab06bcb4f7c5cd3123a2a9a4d3364d4575d27c4b33468bd4497dd094" + url: "https://pub.dev" source: hosted version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: a9b3ea9043eabfaadfa3fb89de67a11210d85569086d22b3854484beab8b3978 + url: "https://pub.dev" source: hosted version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "80b860b31a11ebbcbe51b8fe887efc204f3af91522f3b51bcda4622d276d2120" + url: "https://pub.dev" source: hosted version: "2.1.0" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "15fd9dbb306d5efce57dcf62dcb1ae045fbf74079ab4464a950e099bf5800deb" + url: "https://pub.dev" source: hosted version: "2.0.12" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: e3c3b16d3104260c10eea3b0e34272aaa57921f83148b0619f74c2eced9b7ef1 + url: "https://pub.dev" source: hosted version: "3.0.1" url_strategy: dependency: "direct main" description: name: url_strategy - url: "https://pub.dartlang.org" + sha256: "42b68b42a9864c4d710401add17ad06e28f1c1d5500c93b98c431f6b0ea4ab87" + url: "https://pub.dev" source: hosted version: "0.2.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "9.4.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: e42dfcc48f67618344da967b10f62de57e04bae01d9d3af4c2596f3712a88c99 + url: "https://pub.dev" source: hosted version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + url: "https://pub.dev" source: hosted version: "2.2.0" webdriver: dependency: transitive description: name: webdriver - url: "https://pub.dartlang.org" + sha256: ef67178f0cc7e32c1494645b11639dd1335f1d18814aa8435113a92e9ef9d841 + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.1" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: "6b75ac2ddd42f5c226fdaf4498a2b04071c06f1f2b8f7ab1c3f77cc7f2285ff1" + url: "https://pub.dev" source: hosted version: "2.7.0" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: "060b6e1c891d956f72b5ac9463466c37cce3fa962a921532fc001e86fe93438e" + url: "https://pub.dev" source: hosted version: "0.2.0+1" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: "80d494c09849dc3f899d227a78c30c5b949b985ededf884cb3f3bcd39f4b447a" + url: "https://pub.dev" source: hosted version: "5.4.1" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index be0579d0885d..dc2acb404b5f 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -23,7 +23,7 @@ publish_to: 'none' version: 0.1.0 environment: - sdk: '>=2.18.1 <3.0.0' + sdk: '>=2.19.2 <4.0.0' flutter: '>=3.3.2' dependencies: diff --git a/learning/tour-of-beam/terraform/README.md b/learning/tour-of-beam/terraform/README.md new file mode 100644 index 000000000000..3b29bf072fe4 --- /dev/null +++ b/learning/tour-of-beam/terraform/README.md @@ -0,0 +1,121 @@ + +# The Tour of Beam deployment on GCP +This guide provides instructions on how to deploy the Tour of Beam environment on Google Cloud Platform (GCP) and Firebase environment. Before starting the deployment, ensure that you have the following prerequisites in place: + +## Prerequisites: + +1. [GCP project](https://cloud.google.com/resource-manager/docs/creating-managing-projects) +2. [GCP User account](https://cloud.google.com/appengine/docs/standard/access-control?tab=python) _(Note: You will find the instruction "How to create User account" for your new project)_
+ Ensure that the account has at least following privileges: + - Cloud Datastore Owner + - Create Service Accounts + - Security Admin + - Service Account User + - Service Usage Admin + - Storage Admin + - Kubernetes Engine Cluster Viewer + +3. [Google Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) for saving deployment state + +4. An OS with the following software installed: + +* [Java](https://adoptopenjdk.net/) +* [NodeJS & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/) +* [Flutter (3.7.3 >)](https://docs.flutter.dev/get-started/install) +* [Dart SDK (2.19.2)](https://dart.dev/get-dart) +* [Firebase-tools CLI](https://www.npmjs.com/package/firebase-tools) +* [Terraform](https://www.terraform.io/downloads) +* [gcloud CLI](https://cloud.google.com/sdk/docs/install-sdk) +* [Kubectl authentication plugin](https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke) +* [Go](https://go.dev/doc/install) + +5. Apache Beam Git repository cloned locally + +# Prepare deployment configuration: +Tour of Beam backend uses `terraform.tfvars` located in `learning/tour-of-beam/terraform/environment/environment_name/` to define variables specific to an environment (e.g., prod, test, staging). Follow the steps below to prepare the deployment configuration:
+1. Create a folder (referred to as `environment_name`) to define a new environment and place configuration files into it: + +* `terraform.tfvars` environment variables: +``` +project_id = "gcp_project_id" # Your GCP Project ID +cloudfunctions_bucket = "gcs_bucket_name" # Globally unique name of the bucket to store cloud functions' source code +region = "gcp_region" # Your GCP resources region +service_account_id = "service_account_name" # Name of GCP service account to run Tour of Beam cloud functions + +``` +* `state.tfbackend` environment variables: +``` +bucket = "bucket_name" # Your created bucket name for terraform tfstate file +``` +2. Configure authentication for the Google Cloud Platform (GCP) +``` +gcloud init +``` +``` +gcloud auth application-default login +``` + +3. Configure authentication in the GCP Docker registry: +``` + gcloud auth configure-docker `chosen_region`-docker.pkg.dev +``` +4. And the authentication in GCP Google Kubernetes Engine: +``` +gcloud container clusters get-credentials --region `chosen_gke_zone` `gke_name` --project `project_id` +``` + +# Deploy the Tour of Beam Backend: + +5. Run the following command from the top-level repository folder ("beam") to deploy the Tour of Beam Backend infrastructure: +``` +./gradlew learning:tour-of-beam:terraform:InitBackend -Pproject_environment="environment_name" -Pproject_id="gcp-project-id" -Pgcloud_account=`gcloud config get-value core/account` +``` +Where: +- **project_environment** - environment name +- **project_id** - name of your GCP Project ID + +# Deploy the Tour of Beam Frontend: + +6. Run the following command and follow the instructions to configure authentication for Firebase: +``` +firebase login --no-localhost +``` + +7. Run the following command from the top-level repository folder ("beam") to deploy the Tour of Beam Frontend infrastructure: +``` +./gradlew learning:tour-of-beam:terraform:InitFrontend -Pproject_environment="environment_name" -Pproject_id="gcp-project-id" -Pdns-name="playground-dns-name" -Pregion="gcp-region" -Pwebapp_id="firebase_webapp_name" +``` +Where: +- **project_environment** - environment name +- **project_id** - name of your GCP Project ID +- **dns-name** - DNS name reserved for Beam Playground +- **region** - name of your GCP Resources region +- **webapp_id** - name of your Firebase Web Application that will be created (example: Tour-of-Beam-Web-App) + +# Validate the deployment of the Tour of Beam: +8. Open the Tour of Beam webpage in a web browser (Hosting URL will be provided in terminal output) to ensure that deployment has been successfully completed. + +Example: +``` +✔ Deploy complete! + +Project Console: https://console.firebase.google.com/project/some-gcp-project-id/overview +Hosting URL: https://some-gcp-project-id.web.app +``` \ No newline at end of file diff --git a/learning/tour-of-beam/terraform/api_enable/main.tf b/learning/tour-of-beam/terraform/api_enable/main.tf new file mode 100644 index 000000000000..3a61a090fe9e --- /dev/null +++ b/learning/tour-of-beam/terraform/api_enable/main.tf @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +resource "google_project_service" "required_services" { + project = var.project_id + for_each = toset([ + "cloudresourcemanager", + "iam", + "cloudbuild", + "cloudfunctions", + "firebase" + ]) + service = "${each.key}.googleapis.com" + disable_on_destroy = false +} diff --git a/learning/tour-of-beam/terraform/api_enable/variables.tf b/learning/tour-of-beam/terraform/api_enable/variables.tf new file mode 100644 index 000000000000..f4a375110500 --- /dev/null +++ b/learning/tour-of-beam/terraform/api_enable/variables.tf @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +variable "project_id" { + description = "The ID of the Google Cloud project within which resources are provisioned" +} diff --git a/learning/tour-of-beam/terraform/build.gradle.kts b/learning/tour-of-beam/terraform/build.gradle.kts new file mode 100644 index 000000000000..4406861d4ed4 --- /dev/null +++ b/learning/tour-of-beam/terraform/build.gradle.kts @@ -0,0 +1,388 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.pswidersk.gradle.terraform.TerraformTask +import java.io.ByteArrayOutputStream +import java.util.regex.Pattern + +plugins { + id("com.pswidersk.terraform-plugin") version "1.0.0" +} + +terraformPlugin { + terraformVersion.set("1.0.9") +} + +/* init Infrastructure for migrate */ +tasks.register("terraformInit") { + // exec args can be passed by commandline, for example + var environment = project.property("project_environment") as String + args( + "init", "-migrate-state", + "-backend-config=./environment/$environment/state.tfbackend", + "-var=environment=$environment", + if (file("./environment/$environment/terraform.tfvars").exists()) { + "-var-file=./environment/$environment/terraform.tfvars" + } else { + "-no-color" + } + ) + } + + /* refresh Infrastucture for remote state */ +tasks.register("terraformRef") { + var environment = project.property("project_environment") as String + args( + "refresh", + "-lock=false", + "-var=environment=$environment", + if (file("./environment/$environment/terraform.tfvars").exists()) { + "-var-file=./environment/$environment/terraform.tfvars" + } else { + "-no-color" + } + ) + } + +tasks.register("terraformApplyBackend") { + group = "backend-deploy" + var pg_router_host = project.extensions.extraProperties["pg_router_host"] as String + var environment = project.property("project_environment") as String + var gcloud_account = project.property("gcloud_account") as String + args( + "apply", + "-auto-approve", + "-lock=false", + "-parallelism=3", + "-var=pg_router_host=$pg_router_host", + "-var=gcloud_init_account=$gcloud_account", + "-var=environment=$environment", + if (file("./environment/$environment/terraform.tfvars").exists()) { + "-var-file=./environment/$environment/terraform.tfvars" + } else { + "-no-color" + } + ) + tasks.getByName("uploadLearningMaterials").mustRunAfter(this) + + } + +tasks.register("terraformDestroy") { + var pg_router_host = project.extensions.extraProperties["pg_router_host"] as String + var environment = project.property("project_environment") as String + var gcloud_account = project.property("gcloud_account") as String + args( + "destroy", + "-auto-approve", + "-lock=false", + "-var=pg_router_host=$pg_router_host", + "-var=environment=$environment", + "-var=gcloud_init_account=$gcloud_account", + if (file("./environment/$environment/terraform.tfvars").exists()) { + "-var-file=./environment/$environment/terraform.tfvars" + } else { + "-no-color" + } + ) +} + +tasks.register("getRouterHost") { + group = "backend-deploy" + val result = ByteArrayOutputStream() + exec { + commandLine("kubectl", "get", "svc", "-l", "app=backend-router-grpc", "-o", "jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}:{.items[0].spec.ports[0].port}'") + standardOutput = result + } + val pg_router_host = result.toString().trim().replace("'", "") + project.extensions.extraProperties["pg_router_host"] = pg_router_host +} + +tasks.register("indexcreate") { + group = "backend-deploy" + val indexpath = "../backend/internal/storage/index.yaml" + exec { + executable("gcloud") + args("datastore", "indexes", "create", indexpath) + } +} + +tasks.register("firebaseProjectCreate") { + group = "frontend-deploy" + val result = ByteArrayOutputStream() + var project_id = project.property("project_id") as String + exec { + executable("firebase") + args("projects:list") + standardOutput = result + } + val output = result.toString().trim() + if (output.contains(project_id)) { + println("Firebase is already added to project $project_id.") + } else { + exec { + executable("firebase") + args("projects:addfirebase", project_id) + }.assertNormalExitValue() + println("Firebase has been added to project $project_id.") + } +} + +tasks.register("firebaseWebAppCreate") { + group = "frontend-deploy" + val result = ByteArrayOutputStream() + var project_id = project.property("project_id") as String + var webapp_id = project.property("webapp_id") as String + exec { + executable("firebase") + args("apps:list", "--project", project_id) + standardOutput = result + } + println(result) + val output = result.toString() + if (output.contains(webapp_id)) { + println("Webapp id $webapp_id is already created on the project: $project_id.") + val regex = Regex("$webapp_id[│ ]+([\\w:]+)[│ ]+WEB[│ ]+") + val firebaseAppId = regex.find(output)?.groupValues?.get(1)?.trim() + project.extensions.extraProperties["firebaseAppId"] = firebaseAppId + } else { + val result2 = ByteArrayOutputStream() + exec { + executable("firebase") + args("apps:create", "WEB", webapp_id, "--project", project_id) + standardOutput = result2 + }.assertNormalExitValue() + val firebaseAppId = result2.toString().lines().find { it.startsWith(" - App ID:") }?.substringAfter(":")?.trim() + project.extensions.extraProperties["firebaseAppId"] = firebaseAppId + println("Firebase app ID for newly created Firebase Web App: $firebaseAppId") + } +} + +// firebase apps:sdkconfig WEB AppId +tasks.register("getSdkConfigWebApp") { + group = "frontend-deploy" + val firebaseAppId = project.extensions.extraProperties["firebaseAppId"] as String + val result = ByteArrayOutputStream() + exec { + executable("firebase") + args("apps:sdkconfig", "WEB", firebaseAppId) + standardOutput = result + } + val output = result.toString().trim() + val pattern = Pattern.compile("\\{[^{]*\"locationId\":\\s*\".*?\"[^}]*\\}", Pattern.DOTALL) + val matcher = pattern.matcher(output) + if (matcher.find()) { + val firebaseConfigData = matcher.group().replace("{", "") + .replace("}", "") + .replace("\"locationId\":\\s*\".*?\",?".toRegex(), "") + .replace("\"(\\w+)\":".toRegex(), "$1:") + .replace(":\\s*\"(.*?)\"".toRegex(), ":\"$1\"") + project.extensions.extraProperties["firebaseConfigData"] = firebaseConfigData.trim() + println("Firebase config data: $firebaseConfigData") + } +} + +tasks.register("prepareFirebaseOptionsDart") { + group = "frontend-deploy" + val firebaseConfigData = project.extensions.extraProperties["firebaseConfigData"] as String + val file = project.file("../frontend/lib/firebase_options.dart") + val content = file.readText() + val updatedContent = content.replace(Regex("""static const FirebaseOptions web = FirebaseOptions\(([^)]+)\);"""), "static const FirebaseOptions web = FirebaseOptions(${firebaseConfigData});") + file.writeText(updatedContent) +} + +tasks.register("flutterPubGetPG") { + exec { + executable("flutter") + args("pub", "get") + workingDir("../../../playground/frontend/playground_components") + } +} + +tasks.register("flutterPubRunPG") { + exec { + executable("flutter") + args("pub", "run", "build_runner", "build", "--delete-conflicting-outputs") + workingDir("../../../playground/frontend/playground_components") + } +} + +tasks.register("flutterPubGetTob") { + exec { + executable("flutter") + args("pub", "get") + workingDir("../frontend") + } +} + +tasks.register("flutterPubRunTob") { + exec { + executable("flutter") + args("pub", "run", "build_runner", "build", "--delete-conflicting-outputs") + workingDir("../frontend") + } +} + +tasks.register("flutterBuildWeb") { + exec { + executable("flutter") + args("build", "web", "--profile", "--dart-define=Dart2jsOptimization=O0") + workingDir("../frontend") + } +} + +tasks.register("firebaseDeploy") { + var project_id = project.property("project_id") as String + exec { + commandLine("firebase", "deploy", "--project", project_id) + workingDir("../frontend") + } +} + +tasks.register("prepareConfig") { + group = "frontend-deploy" + var region = project.property("region") as String + var project_id = project.property("project_id") as String + var environment = project.property("project_environment") as String + var dns_name = project.property("dns-name") as String + val configFileName = "config.dart" + val modulePath = project(":learning:tour-of-beam:frontend").projectDir.absolutePath + val file = File("$modulePath/lib/$configFileName") + + file.writeText( + """ +const _cloudFunctionsProjectRegion = '$region'; +const _cloudFunctionsProjectId = '$project_id'; +const cloudFunctionsBaseUrl = 'https://' + '$region-$project_id' + '.cloudfunctions.net/${environment}_'; + + +const String kAnalyticsUA = 'UA-73650088-2'; +const String kApiClientURL = +'https://router.${dns_name}'; +const String kApiJavaClientURL = +'https://java.${dns_name}'; +const String kApiGoClientURL = +'https://go.${dns_name}'; +const String kApiPythonClientURL = +'https://python.${dns_name}'; +const String kApiScioClientURL = +'https://scio.${dns_name}'; +""" + ) +} + +tasks.register("prepareFirebasercConfig") { + group = "frontend-deploy" + var project_id = project.property("project_id") as String + val configFileName = ".firebaserc" + val modulePath = project(":learning:tour-of-beam:frontend").projectDir.absolutePath + val file = File("$modulePath/$configFileName") + + file.writeText( + """ +{ + "projects": { + "default": "$project_id" + } +} +""" + ) +} + +tasks.register("uploadLearningMaterials") { + var project_id = project.property("project_id") as String + group = "backend-deploy" + exec { + commandLine("go", "run", "cmd/ci_cd/ci_cd.go") + environment("DATASTORE_PROJECT_ID", project_id) + environment("GOOGLE_PROJECT_ID", project_id) + environment("TOB_LEARNING_ROOT", "../learning-content/") + workingDir("../backend") + } + dependsOn("terraformApplyBackend") + mustRunAfter("terraformApplyBackend") +} + +/* Tour of Beam backend init */ +tasks.register("InitBackend") { + group = "backend-deploy" + val getRouterHost = tasks.getByName("getRouterHost") + val indexCreate = tasks.getByName("indexcreate") + val tfInit = tasks.getByName("terraformInit") + val tfApplyBackend = tasks.getByName("terraformApplyBackend") + val uploadLearningMaterials = tasks.getByName("uploadLearningMaterials") + dependsOn(getRouterHost) + dependsOn(indexCreate) + dependsOn(tfInit) + dependsOn(tfApplyBackend) + dependsOn(uploadLearningMaterials) + indexCreate.mustRunAfter(getRouterHost) + tfInit.mustRunAfter(indexCreate) + tfApplyBackend.mustRunAfter(tfInit) + uploadLearningMaterials.mustRunAfter(tfApplyBackend) + +} + +tasks.register("DestroyBackend") { + group = "backend-destroy" + val getRouterHost = tasks.getByName("getRouterHost") + val terraformDestroy = tasks.getByName("terraformDestroy") + dependsOn(getRouterHost) + dependsOn(terraformDestroy) + terraformDestroy.mustRunAfter(getRouterHost) +} + +tasks.register("InitFrontend") { + group = "frontend-deploy" + val prepareConfig = tasks.getByName("prepareConfig") + val prepareFirebasercConfig = tasks.getByName("prepareFirebasercConfig") + val firebaseProjectCreate = tasks.getByName("firebaseProjectCreate") + val firebaseWebAppCreate = tasks.getByName("firebaseWebAppCreate") + val getSdkConfigWebApp = tasks.getByName("getSdkConfigWebApp") + val prepareFirebaseOptionsDart = tasks.getByName("prepareFirebaseOptionsDart") + val flutterPubGetPG = tasks.getByName("flutterPubGetPG") + val flutterPubRunPG = tasks.getByName("flutterPubRunPG") + val flutterPubGetTob = tasks.getByName("flutterPubGetTob") + val flutterPubRunTob = tasks.getByName("flutterPubRunTob") + val flutterBuildWeb = tasks.getByName("flutterBuildWeb") + val firebaseDeploy = tasks.getByName("firebaseDeploy") + dependsOn(prepareConfig) + dependsOn(prepareFirebasercConfig) + dependsOn(firebaseProjectCreate) + dependsOn(firebaseWebAppCreate) + dependsOn(getSdkConfigWebApp) + dependsOn(prepareFirebaseOptionsDart) + dependsOn(flutterPubGetPG) + dependsOn(flutterPubRunPG) + dependsOn(flutterPubGetTob) + dependsOn(flutterPubRunTob) + dependsOn(flutterBuildWeb) + dependsOn(firebaseDeploy) + prepareFirebasercConfig.mustRunAfter(prepareConfig) + firebaseProjectCreate.mustRunAfter(prepareFirebasercConfig) + firebaseWebAppCreate.mustRunAfter(firebaseProjectCreate) + getSdkConfigWebApp.mustRunAfter(firebaseWebAppCreate) + prepareFirebaseOptionsDart.mustRunAfter(getSdkConfigWebApp) + flutterPubGetPG.mustRunAfter(prepareFirebaseOptionsDart) + flutterPubRunPG.mustRunAfter(flutterPubGetPG) + flutterPubGetTob.mustRunAfter(flutterPubRunPG) + flutterPubRunTob.mustRunAfter(flutterPubGetTob) + flutterBuildWeb.mustRunAfter(flutterPubRunTob) + firebaseDeploy.mustRunAfter(flutterBuildWeb) +} diff --git a/learning/tour-of-beam/terraform/cloud_functions/main.tf b/learning/tour-of-beam/terraform/cloud_functions/main.tf new file mode 100644 index 000000000000..baa3813c5ce1 --- /dev/null +++ b/learning/tour-of-beam/terraform/cloud_functions/main.tf @@ -0,0 +1,59 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +resource "google_cloudfunctions_function" "cloud_function" { + count = length(var.entry_point_names) + name = "${var.environment}_${var.entry_point_names[count.index]}" + runtime = "go116" + available_memory_mb = 128 + project = var.project_id + service_account_email = var.service_account_id + source_archive_bucket = var.source_archive_bucket + source_archive_object = var.source_archive_object + region = var.region + ingress_settings = "ALLOW_ALL" + # Get the source code of the cloud function as a Zip compression + trigger_http = true + # Name of the function that will be executed when the Google Cloud Function is triggered + entry_point = var.entry_point_names[count.index] + + environment_variables = { + DATASTORE_PROJECT_ID=var.project_id + GOOGLE_PROJECT_ID=var.project_id + PLAYGROUND_ROUTER_HOST=var.pg_router_host + } + + timeouts { + create = "20m" + delete = "20m" + } + +} + +# Create IAM entry so all users can invoke the function +resource "google_cloudfunctions_function_iam_member" "invoker" { + count = length(google_cloudfunctions_function.cloud_function) + project = google_cloudfunctions_function.cloud_function[count.index].project + region = google_cloudfunctions_function.cloud_function[count.index].region + cloud_function = google_cloudfunctions_function.cloud_function[count.index].name + + role = "roles/cloudfunctions.invoker" + member = "allUsers" + + depends_on = [google_cloudfunctions_function.cloud_function] +} diff --git a/learning/tour-of-beam/terraform/cloud_functions/output.tf b/learning/tour-of-beam/terraform/cloud_functions/output.tf new file mode 100644 index 000000000000..a8ba150ed5f9 --- /dev/null +++ b/learning/tour-of-beam/terraform/cloud_functions/output.tf @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +output "cloud-function-trigger-url" { + value = google_cloudfunctions_function.cloud_function.*.https_trigger_url +} diff --git a/learning/tour-of-beam/terraform/cloud_functions/variables.tf b/learning/tour-of-beam/terraform/cloud_functions/variables.tf new file mode 100644 index 000000000000..3a3ab42d0540 --- /dev/null +++ b/learning/tour-of-beam/terraform/cloud_functions/variables.tf @@ -0,0 +1,46 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +variable "service_account_id" { + description = "The name of Service Account to run Cloud Function" +} + +variable "project_id" { + description = "The GCP Project ID of function" +} + +variable "region" { + description = "The GCP Region of function" +} + +variable "source_archive_bucket" { + description = "The GCS bucket containing the zip archive which contains the function" +} +variable "source_archive_object" { + description = "The source archive object (file) in archive bucket" +} + +variable "entry_point_names" { + type = list + default = ["getSdkList", "getContentTree", "getUnitContent", "getUserProgress", "postUnitComplete", "postUserCode", "postDeleteProgress"] +} + +variable "pg_router_host" { + description = "Hostname:port of Playground GKE cluster's router grpc workload" +} + +variable "environment" {} diff --git a/learning/tour-of-beam/terraform/environment/test/state.tfbackend b/learning/tour-of-beam/terraform/environment/test/state.tfbackend new file mode 100644 index 000000000000..93e7554cf8cb --- /dev/null +++ b/learning/tour-of-beam/terraform/environment/test/state.tfbackend @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +bucket = "tfstate-bucket-tob-1" diff --git a/learning/tour-of-beam/terraform/functions_buckets/main.tf b/learning/tour-of-beam/terraform/functions_buckets/main.tf new file mode 100644 index 000000000000..41fbffbbd2c0 --- /dev/null +++ b/learning/tour-of-beam/terraform/functions_buckets/main.tf @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +resource "google_storage_bucket" "cloud_functions_bucket" { + name = var.cloudfunctions_bucket + location = var.region + storage_class = "STANDARD" +} + +resource "google_storage_bucket_object" "zip" { + # Use an MD5 here. If there's no changes to the source code, this won't change either. + # We can avoid unnecessary redeployments by validating the code is unchanged, and forcing + # a redeployment when it has! + name = "${data.archive_file.source_code.output_md5}.zip" + bucket = google_storage_bucket.cloud_functions_bucket.name + source = data.archive_file.source_code.output_path + content_type = "application/zip" +} diff --git a/learning/tour-of-beam/terraform/functions_buckets/output.tf b/learning/tour-of-beam/terraform/functions_buckets/output.tf new file mode 100644 index 000000000000..e2f16108f54a --- /dev/null +++ b/learning/tour-of-beam/terraform/functions_buckets/output.tf @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +output "functions-bucket-id" { + value = google_storage_bucket.cloud_functions_bucket.id +} + +output "functions-bucket-name" { + value = google_storage_bucket.cloud_functions_bucket.name +} + +output "function-bucket-object" { + value = google_storage_bucket_object.zip.name +} diff --git a/learning/tour-of-beam/terraform/functions_buckets/variables.tf b/learning/tour-of-beam/terraform/functions_buckets/variables.tf new file mode 100644 index 000000000000..126f66e609e6 --- /dev/null +++ b/learning/tour-of-beam/terraform/functions_buckets/variables.tf @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +#Generates archive of source code +variable "cloudfunctions_bucket" { + description = "The name of the bucket to store cloud functions' source code" +} + +variable "region" { + description = "The GCS region" +} + +data "archive_file" "source_code" { + type = "zip" + source_dir = "../backend" + output_path = "/tmp/backend.zip" +} diff --git a/learning/tour-of-beam/terraform/main.tf b/learning/tour-of-beam/terraform/main.tf new file mode 100644 index 000000000000..04880691a286 --- /dev/null +++ b/learning/tour-of-beam/terraform/main.tf @@ -0,0 +1,48 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module "setup" { + source = "./setup" + project_id = var.project_id + service_account_id = var.service_account_id + gcloud_init_account = var.gcloud_init_account + depends_on = [module.api_enable] +} + +module "functions_buckets" { + source = "./functions_buckets" + region = var.region + cloudfunctions_bucket = var.cloudfunctions_bucket + depends_on = [module.setup, module.api_enable] +} + +module "api_enable" { + source = "./api_enable" + project_id = var.project_id +} + +module "cloud_functions" { + source = "./cloud_functions" + region = var.region + project_id = var.project_id + pg_router_host = var.pg_router_host + environment = var.environment + service_account_id = module.setup.service-account-email + source_archive_bucket = module.functions_buckets.functions-bucket-name + source_archive_object = module.functions_buckets.function-bucket-object + depends_on = [module.functions_buckets, module.setup, module.api_enable] +} diff --git a/learning/tour-of-beam/terraform/output.tf b/learning/tour-of-beam/terraform/output.tf new file mode 100644 index 000000000000..f85f61497df3 --- /dev/null +++ b/learning/tour-of-beam/terraform/output.tf @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +output "service-account-email" { + value = module.setup.service-account-email +} + +output "cloud-function-trigger-url" { + value = module.cloud_functions.cloud-function-trigger-url +} + +output "functions-bucket-name" { + value = module.functions_buckets.functions-bucket-name +} + +output "function-bucket-object" { + value = module.functions_buckets.function-bucket-object +} diff --git a/learning/tour-of-beam/terraform/provider.tf b/learning/tour-of-beam/terraform/provider.tf new file mode 100644 index 000000000000..df421ee1fad4 --- /dev/null +++ b/learning/tour-of-beam/terraform/provider.tf @@ -0,0 +1,35 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +terraform { + backend "gcs" { + } + + required_providers { + google = { + source = "hashicorp/google" + version = "4.4.0" + } + } +} + +provider "google" { + project = var.project_id + region = var.region +} diff --git a/learning/tour-of-beam/terraform/setup/iam.tf b/learning/tour-of-beam/terraform/setup/iam.tf new file mode 100644 index 000000000000..842f16380658 --- /dev/null +++ b/learning/tour-of-beam/terraform/setup/iam.tf @@ -0,0 +1,41 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +resource "google_service_account" "cloud_function_sa" { + account_id = var.service_account_id + display_name = "Service Account to run Cloud Functions" +} + +resource "google_project_iam_member" "terraform_service_account_roles" { + for_each = toset([ + "roles/cloudfunctions.admin", "roles/storage.objectViewer", + "roles/iam.serviceAccountUser", "roles/datastore.user", + "roles/firebaseauth.viewer" + ]) + role = each.key + member = "serviceAccount:${google_service_account.cloud_function_sa.email}" + project = var.project_id +} + +resource "google_project_iam_member" "gcloud_user_required_roles" { + for_each = toset([ + "roles/cloudfunctions.admin", "roles/firebase.admin" + ]) + role = each.key + member = "user:${var.gcloud_init_account}" + project = var.project_id +} diff --git a/learning/tour-of-beam/terraform/setup/output.tf b/learning/tour-of-beam/terraform/setup/output.tf new file mode 100644 index 000000000000..cc3d34791868 --- /dev/null +++ b/learning/tour-of-beam/terraform/setup/output.tf @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +output "service-account-email" { + value = google_service_account.cloud_function_sa.email +} diff --git a/learning/tour-of-beam/terraform/setup/variables.tf b/learning/tour-of-beam/terraform/setup/variables.tf new file mode 100644 index 000000000000..39898e69002e --- /dev/null +++ b/learning/tour-of-beam/terraform/setup/variables.tf @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +variable "project_id" { + description = "The ID of the Google Cloud project within which resources are provisioned" +} + +variable "service_account_id" { + description = "The name of Service Account to run Cloud Function" +} + +variable "gcloud_init_account" { + description = "User Account ID logged in with gcloud init command (e.g. username@domain.com)" +} \ No newline at end of file diff --git a/learning/tour-of-beam/terraform/variables.tf b/learning/tour-of-beam/terraform/variables.tf new file mode 100644 index 000000000000..87d2b8c07236 --- /dev/null +++ b/learning/tour-of-beam/terraform/variables.tf @@ -0,0 +1,41 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +variable "cloudfunctions_bucket" { + description = "The bucket name that will store functions' source code" +} + +variable "project_id" { + description = "The ID of the Google Cloud project within which resources are provisioned" +} + +variable "service_account_id" { + description = "The ID of the service account responsible for running Google Cloud functions" + default = "tourofbeam-cloudfunction-sa" +} + +variable "region" { + description = "The region of the Google Cloud project within which resources are provisioned" +} + +variable "gcloud_init_account" { + description = "User Account ID logged in with gcloud init command (e.g. username@domain.com)" +} + +variable "pg_router_host" {} + +variable "environment" {} diff --git a/playground/frontend/README.md b/playground/frontend/README.md index 440a0d0d627b..705e96b9d843 100644 --- a/playground/frontend/README.md +++ b/playground/frontend/README.md @@ -146,7 +146,7 @@ flutter format ./lib To delete all generated files and re-generate them again and then run tests: ```bash -./gradlew :playground:frontend:playground_components:test +./gradlew :playground:frontend:playground_components::test ./gradlew :playground:frontend:test ``` @@ -218,7 +218,7 @@ To add a new localization (using `fr` as an example): #### 1. Linking to a catalog example by path -`https://play.beam.apache.org/?path=SDK_JAVA_AggregationMax&sdk=java` +`https://play.beam.apache.org/?path=SDK_JAVA/PRECOMPILED_OBJECT_TYPE_KATA/AggregationMax&sdk=java` Handled by `StandardExampleLoader`. @@ -311,7 +311,7 @@ are allowed for loading single examples, for instance: [ { "sdk": "java", - "path": "SDK_JAVA_AggregationMax" + "path": "SDK_JAVA/PRECOMPILED_OBJECT_TYPE_KATA/AggregationMax" }, { "sdk": "go", @@ -323,7 +323,7 @@ are allowed for loading single examples, for instance: Then pass it in`examples` query parameter like this: -`https://play.beam.apache.org/?sdk=go&examples=[{"sdk":"java","path":"SDK_JAVA_AggregationMax"},{"sdk":"go","url":"https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go","readonly":"iam_get_role"}]` +`https://play.beam.apache.org/?sdk=go&examples=[{"sdk":"java","path":"SDK_JAVA/PRECOMPILED_OBJECT_TYPE_KATA/AggregationMax"},{"sdk":"go","url":"https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go","readonly":"iam_get_role"}]` This starts with the Go example loaded from the URL. If SDK is then switched to Java, the `AggregationMax` catalog example is loaded for it. @@ -348,7 +348,7 @@ Use the `