diff --git a/examples/envied_example/lib/constant_case_env.g.dart b/examples/envied_example/lib/constant_case_env.g.dart index bff6d51..da8ca26 100644 --- a/examples/envied_example/lib/constant_case_env.g.dart +++ b/examples/envied_example/lib/constant_case_env.g.dart @@ -8,6 +8,7 @@ part of 'constant_case_env.dart'; // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: .env final class _ConstantCaseEnv { static const String key1 = 'foo'; diff --git a/examples/envied_example/lib/debug_env.g.dart b/examples/envied_example/lib/debug_env.g.dart index 78dd429..44e3a4c 100644 --- a/examples/envied_example/lib/debug_env.g.dart +++ b/examples/envied_example/lib/debug_env.g.dart @@ -8,6 +8,7 @@ part of 'debug_env.dart'; // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: .env_debug final class _Env { static const String key1 = 'debug_foo'; diff --git a/examples/envied_example/lib/env.dart b/examples/envied_example/lib/env.dart index 57bc15b..d18f499 100644 --- a/examples/envied_example/lib/env.dart +++ b/examples/envied_example/lib/env.dart @@ -4,7 +4,7 @@ import 'package:example/example_enum.dart'; part 'env.g.dart'; -@Envied(path: '.env') +@Envied(requireEnvFile: true) final class Env { @EnviedField(varName: 'KEY1') static const String key1 = _Env.key1; diff --git a/examples/envied_example/lib/env.g.dart b/examples/envied_example/lib/env.g.dart index 3f48d61..14bb610 100644 --- a/examples/envied_example/lib/env.g.dart +++ b/examples/envied_example/lib/env.g.dart @@ -8,6 +8,7 @@ part of 'env.dart'; // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: .env final class _Env { static const String key1 = 'foo'; diff --git a/examples/envied_example/lib/nullable_env.g.dart b/examples/envied_example/lib/nullable_env.g.dart index fcbdc1b..c798577 100644 --- a/examples/envied_example/lib/nullable_env.g.dart +++ b/examples/envied_example/lib/nullable_env.g.dart @@ -8,6 +8,7 @@ part of 'nullable_env.dart'; // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: .env final class _NullableEnv { static const String? key6 = 'http://foo.bar/baz'; } diff --git a/examples/envied_example/lib/release_env.g.dart b/examples/envied_example/lib/release_env.g.dart index c56e77e..069b329 100644 --- a/examples/envied_example/lib/release_env.g.dart +++ b/examples/envied_example/lib/release_env.g.dart @@ -8,6 +8,7 @@ part of 'release_env.dart'; // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: .env final class _Env { static const String key1 = 'foo'; diff --git a/examples/envied_example/pubspec.lock b/examples/envied_example/pubspec.lock index b219bce..59ec714 100644 --- a/examples/envied_example/pubspec.lock +++ b/examples/envied_example/pubspec.lock @@ -5,42 +5,47 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "36a321c3d2cbe01cbcb3540a87b8843846e0206df3e691fa7b23e19e78de6d49" + sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77" url: "https://pub.dev" source: hosted - version: "65.0.0" + version: "73.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: dfe03b90ec022450e22513b5e5ca1f01c0c01de9c3fba2f7fd233cb57a6b9a07 + sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.8.0" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.6.0" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" build: dependency: transitive description: @@ -61,34 +66,34 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.13" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.2.11" + version: "7.3.2" built_collection: dependency: transitive description: @@ -101,10 +106,10 @@ packages: dependency: transitive description: name: built_value - sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.7.0" + version: "8.9.2" checked_yaml: dependency: transitive description: @@ -117,96 +122,96 @@ packages: dependency: transitive description: name: code_builder - sha256: b2151ce26a06171005b379ecff6e08d34c470180ffe16b8e14b6d52be292b55f + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.10.1" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" convert: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" coverage: dependency: transitive description: name: coverage - sha256: ac86d3abab0f165e4b8f561280ff4e066bceaac83c424dd19f1ae2c2fcd12ca9 + sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5" url: "https://pub.dev" source: hosted - version: "1.7.1" + version: "1.11.0" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" dart_style: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.7" envied: dependency: "direct main" description: path: "../../packages/envied" relative: true source: path - version: "0.5.3" + version: "1.0.0" envied_generator: dependency: "direct dev" description: path: "../../packages/envied_generator" relative: true source: path - version: "0.5.3" + version: "1.0.0" equatable: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -219,10 +224,10 @@ packages: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" http_multi_server: dependency: transitive description: @@ -235,10 +240,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.1" io: dependency: transitive description: @@ -251,58 +256,66 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" json_annotation: dependency: transitive description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" lints: dependency: "direct dev" description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "5.0.0" logging: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "0.1.2-main.4" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.16.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" node_preamble: dependency: transitive description: @@ -323,10 +336,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.1" pool: dependency: transitive description: @@ -347,10 +360,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" recase: dependency: transitive description: @@ -363,10 +376,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: @@ -379,34 +392,34 @@ packages: dependency: transitive description: name: shelf_static - sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.1" source_gen: dependency: transitive description: name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" source_maps: dependency: transitive description: @@ -427,10 +440,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -451,10 +464,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.0" term_glyph: dependency: transitive description: @@ -467,26 +480,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.5" timing: dependency: transitive description: @@ -499,18 +512,18 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" vm_service: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.3.1" watcher: dependency: transitive description: @@ -519,14 +532,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "3.0.1" webkit_inspection_protocol: dependency: transitive description: @@ -544,4 +573,4 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.5.0 <4.0.0" diff --git a/melos.yaml b/melos.yaml index ac31f01..38b827c 100644 --- a/melos.yaml +++ b/melos.yaml @@ -11,14 +11,23 @@ scripts: test: run: melos exec --no-private -c 1 "dart test --coverage=coverage" env: + ENV1: one + Env2: two + env3: three SYSTEM_VAR: system_var lcov: run: melos exec --no-private -c 1 "dart pub global run coverage:test_with_coverage" env: + ENV1: one + Env2: two + env3: three SYSTEM_VAR: system_var coverage: run: melos exec --no-private -c 1 "dart pub global run code_coverage -u -o" env: + ENV1: one + Env2: two + env3: three SYSTEM_VAR: system_var validate: > melos exec -c 1 "dart analyze && dart format . --set-exit-if-changed" @@ -29,4 +38,7 @@ scripts: env: run: dart run scripts/propagate_readme.dart env: + ENV1: one + Env2: two + env3: three SYSTEM_VAR: 'system_var' diff --git a/packages/envied/README.md b/packages/envied/README.md index 87843f8..06a7f74 100644 --- a/packages/envied/README.md +++ b/packages/envied/README.md @@ -29,6 +29,9 @@ A cleaner way to handle your environment variables in Dart/Flutter. - [Obfuscation/Encryption](#obfuscationencryption) - [**Optional Environment Variables**](#optional-environment-variables) - [**Environment Variable Naming Conventions**](#environment-variable-naming-conventions) + - [Using System Environment Variables](#using-system-environment-variables) + - [Setting file from CLI](#setting-file-from-cli) +- [Known Issues](#known-issues) - [License](#license)
@@ -237,6 +240,55 @@ targets: Note that **both** `path` and `override` must be set for the override to work. +### Using System Environment Variables + +Using the `environment` option in either an `Envied` or `EnviedField` instructs the generator to use the value from the `.env` file as the key for a system environment variable read from `Platform.environment`. + + +For example, let's use the `Envied` class and the following `.env` files: + +```dart +@Envied(environment: true) +final class Env { + @EnviedField(varName: 'API_KEY') + static const String apiKey = _Env.apiKey; +} +``` + +... or ... + +```dart +@Envied() +final class Env { + @EnviedField(environment: true, varName: 'API_KEY') + static const String apiKey = _Env.apiKey; +} +``` + +**latest.env** +```.env +API_KEY=LATEST_API_KEY +``` + +**stage.env** +```.env +API_KEY=STAGE_API_KEY +``` + +Depending on which `.env` file you use to generate can result in the `API_KEY` being read from either `Platform.environment['LATEST_API_KEY']` or `Platform.environment['STAGE_API_KEY']`. This can allow for the `.env` files to be safely checked in to the source control, the specific values to be set at build time, and keep the secrets safely stored in the host environment. + +For instructions on switching the `.env` file at build time, see [Setting file from CLI](#setting-file-from-cli). + +### Setting file from CLI + +To change which `.env` file is used by default using the CLI, pass it in via the `--define` flag as follows: + +```sh +dart run build_runner build --define=envied_generator:envied=path=my_other.env +``` + +This allows you to have multiple `.env` files, one per backend for instance, and then switch which one gets included in the build easily from CI/CD scripts such as github workflows. + ### Known issues When modifying the `.env` file, the generator might not pick up the change due to [dart-lang/build#967](https://github.com/dart-lang/build/issues/967). diff --git a/packages/envied/lib/src/envied_base.dart b/packages/envied/lib/src/envied_base.dart index a80746e..79a66a1 100644 --- a/packages/envied/lib/src/envied_base.dart +++ b/packages/envied/lib/src/envied_base.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + /// Annotation with default options const envied = Envied(); @@ -72,6 +74,13 @@ final class Envied { /// ``` final bool useConstantCase; + /// Whether to read the ultimate values from [Platform.environment] rather + /// than from the `.env` file. When set to true, the value found in the + /// `.env` file will not be used as the ultimate value but will instead be + /// used as the key and the ultimate value will be read from + /// [Platform.environment]. + final bool environment; + /// Whether to interpolate the values for all fields. /// If [interpolate] is `true`, the value will be interpolated /// with the environment variables. @@ -97,6 +106,7 @@ final class Envied { this.name, this.obfuscate = false, this.allowOptionalFields = false, + this.environment = false, this.useConstantCase = false, this.interpolate = true, this.rawStrings = false, @@ -126,6 +136,11 @@ final class EnviedField { /// The default value must be a [String], [bool] or a [num]. final Object? defaultValue; + /// When set to `true`, the value set in the `.env` file will not be used as + /// the ultimate value but will instead be used as the key and the ultimate + /// value will be read from [Platform.environment]. + final bool? environment; + /// Allows this field to be optional when the type is nullable. /// /// With this enabled, the generator will not throw an exception @@ -175,6 +190,7 @@ final class EnviedField { this.varName, this.obfuscate, this.defaultValue, + this.environment, this.optional, this.useConstantCase, this.interpolate, diff --git a/packages/envied_generator/lib/src/generator.dart b/packages/envied_generator/lib/src/generator.dart index 83c36aa..2a9eec5 100644 --- a/packages/envied_generator/lib/src/generator.dart +++ b/packages/envied_generator/lib/src/generator.dart @@ -50,6 +50,8 @@ final class EnviedGenerator extends GeneratorForAnnotation { obfuscate: annotation.read('obfuscate').literalValue as bool, allowOptionalFields: annotation.read('allowOptionalFields').literalValue as bool? ?? false, + environment: + annotation.read('environment').literalValue as bool? ?? false, useConstantCase: annotation.read('useConstantCase').literalValue as bool? ?? false, interpolate: annotation.read('interpolate').literalValue as bool? ?? true, @@ -84,8 +86,9 @@ final class EnviedGenerator extends GeneratorForAnnotation { ]), ); - const String ignore = '// coverage:ignore-file\n' - '// ignore_for_file: type=lint'; + final String ignore = '// coverage:ignore-file\n' + '// ignore_for_file: type=lint\n' + '// generated_from: ${config.path}'; return DartFormatter().format('$ignore\n${cls.accept(emitter)}'); } @@ -104,6 +107,9 @@ final class EnviedGenerator extends GeneratorForAnnotation { late String varName; + final bool environment = + reader.read('environment').literalValue as bool? ?? config.environment; + final bool useConstantCase = reader.read('useConstantCase').literalValue as bool? ?? config.useConstantCase; @@ -118,7 +124,24 @@ final class EnviedGenerator extends GeneratorForAnnotation { late final EnvVal? varValue; - if (envs.containsKey(varName)) { + if (environment) { + final String? envKey = envs[varName]?.raw; + if (envKey == null) { + throw InvalidGenerationSourceError( + 'Expected to find an .env entry with a key of `$varName` for field `${field.name}` but none was found.', + element: field, + ); + } + final String? env = Platform.environment[envKey]; + if (env == null) { + throw InvalidGenerationSourceError( + 'Expected to find an System environment variable named `$envKey` for field `${field.name}` but no value was found.', + element: field, + ); + } + + varValue = EnvVal(raw: env); + } else if (envs.containsKey(varName)) { varValue = envs[varName]; } else if (Platform.environment.containsKey(varName)) { varValue = EnvVal(raw: Platform.environment[varName]!); diff --git a/packages/envied_generator/test/.env.environment b/packages/envied_generator/test/.env.environment new file mode 100644 index 0000000..d5ef864 --- /dev/null +++ b/packages/envied_generator/test/.env.environment @@ -0,0 +1,4 @@ +env1=ENV1 +env2=Env2 +env3=env3 +missing_env=MISSING_ENV \ No newline at end of file diff --git a/packages/envied_generator/test/src/generator_tests.dart b/packages/envied_generator/test/src/generator_tests.dart index 0c9f5e0..585ab8a 100644 --- a/packages/envied_generator/test/src/generator_tests.dart +++ b/packages/envied_generator/test/src/generator_tests.dart @@ -14,12 +14,15 @@ const foo = 'bar'; @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: .env final class _Env0 {} ''') @Envied() abstract class Env0 {} -@ShouldThrow("Environment variable file doesn't exist at `.env`.") +@ShouldThrow( + "Environment variable file doesn't exist at `${const String.fromEnvironment('ENV_PATH', defaultValue: '.env')}`.", +) @Envied(requireEnvFile: true) abstract class Env1 {} @@ -98,6 +101,7 @@ abstract class Env7 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env8 { static const String testString = 'testString'; @@ -143,6 +147,7 @@ abstract class Env8 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env8b { static const String? testString = 'testString'; @@ -176,6 +181,7 @@ abstract class Env8b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env9 { static const String testString = 'test_string'; } @@ -189,6 +195,7 @@ abstract class Env9 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env9b { static const String? testString = 'test_string'; } @@ -202,6 +209,7 @@ abstract class Env9b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env9c { static const String testUnescapedString = r'bar$'; } @@ -215,6 +223,7 @@ abstract class Env9c { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env10 { static const String systemVar = 'system_var'; } @@ -228,6 +237,7 @@ abstract class Env10 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env10b { static const String? systemVar = 'system_var'; } @@ -241,6 +251,7 @@ abstract class Env10b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Foo { static const String testString = 'test_string'; } @@ -254,6 +265,7 @@ abstract class Env11 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Foo { static const String? testString = 'test_string'; } @@ -334,6 +346,7 @@ abstract class Env14 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env14b { static const String? testDefaultParam = null; } @@ -347,6 +360,7 @@ abstract class Env14b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env15 { static const String testDefaultParam = 'test_'; @@ -380,6 +394,7 @@ abstract class Env15 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env15b { static const String? testDefaultParam = 'test_'; @@ -409,6 +424,7 @@ abstract class Env15b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env15c { static const String testDefaultParam = r'test_'; @@ -438,6 +454,7 @@ abstract class Env15c { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env16 { static const String testDefaultParam = 'test_'; } @@ -451,6 +468,7 @@ abstract class Env16 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env16b { static const String? testDefaultParam = 'test_'; } @@ -638,6 +656,7 @@ abstract class Env25b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env26 { static final String? foo = null; } @@ -651,6 +670,7 @@ abstract class Env26 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env27 { static final int? foo = null; } @@ -664,6 +684,7 @@ abstract class Env27 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env28 { static final bool? foo = null; } @@ -677,6 +698,7 @@ abstract class Env28 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env29 { static final Uri testUrl = Uri.parse('https://foo.bar/baz'); } @@ -697,6 +719,7 @@ abstract class Env29invalid { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env29b { static final Uri? testUrl = Uri.parse('https://foo.bar/baz'); } @@ -761,6 +784,7 @@ abstract class Env29dInvalid { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env29empty { static final Uri emptyTestUrl = Uri.parse(''); } @@ -774,6 +798,7 @@ abstract class Env29empty { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env30 { static final DateTime testDateTime = DateTime.parse('2023-11-06T22:32:55.287Z'); @@ -788,6 +813,7 @@ abstract class Env30 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env30b { static final DateTime? testDateTime = DateTime.parse('2023-11-06T22:32:55.287Z'); @@ -874,6 +900,7 @@ abstract class Env30dInvalid { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env31 { static final DateTime testDate = DateTime.parse('2023-11-06'); } @@ -887,6 +914,7 @@ abstract class Env31 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env31b { static final DateTime? testDate = DateTime.parse('2023-11-06'); } @@ -1022,6 +1050,7 @@ abstract class Env33b { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env34 { static const String? testDefaultParam = 'test_'; @@ -1059,6 +1088,7 @@ abstract class Env34 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env35 { static final ExampleEnum testEnum = ExampleEnum.values.byName('ipsum'); } @@ -1072,6 +1102,7 @@ abstract class Env35 { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env35b { static final ExampleEnum? testEnum = ExampleEnum.values.byName('ipsum'); } @@ -1153,6 +1184,7 @@ abstract class Env35dInvalid { @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example final class _Env36 { static final Uri testQueryVars = Uri.parse('https://www.my-awesome-website.com/index.php?foo=bar&baz=qux'); @@ -1165,3 +1197,107 @@ abstract class Env36 { ) static final Uri? testQueryVars = null; } + +@ShouldGenerate(r''' +// coverage:ignore-file +// ignore_for_file: type=lint +// generated_from: test/.env.environment +final class _Env37 { + static const String env1 = 'one'; + + static const String env2 = 'two'; + + static const String env3 = 'three'; +} +''') +@Envied( + environment: true, + path: 'test/.env.environment', +) +abstract class Env37 { + @EnviedField() + static final String? env1 = null; + + @EnviedField() + static final String? env2 = null; + + @EnviedField() + static final String? env3 = null; +} + +@ShouldThrow( + 'Expected to find an .env entry with a key of `env4` for field `env4` but none was found.', +) +@Envied( + environment: true, + path: 'test/.env.environment', +) +abstract class Env37b { + @EnviedField() + static final String env4 = ''; +} + +@ShouldGenerate(r''' +// coverage:ignore-file +// ignore_for_file: type=lint +// generated_from: test/.env.environment +final class _Env37c { + static const String env1 = 'ENV1'; + + static const String env2 = 'Env2'; + + static const String env3 = 'three'; +} +''') +@Envied( + environment: true, + path: 'test/.env.environment', +) +abstract class Env37c { + @EnviedField(environment: false) + static final String? env1 = null; + + @EnviedField(environment: false) + static final String? env2 = null; + + @EnviedField() + static final String? env3 = null; +} + +@ShouldGenerate(r''' +// coverage:ignore-file +// ignore_for_file: type=lint +// generated_from: test/.env.environment +final class _Env37d { + static const String env1 = 'ENV1'; + + static const String env2 = 'Env2'; + + static const String env3 = 'three'; +} +''') +@Envied( + path: 'test/.env.environment', +) +abstract class Env37d { + @EnviedField() + static final String? env1 = null; + + @EnviedField() + static final String? env2 = null; + + @EnviedField(environment: true) + static final String? env3 = null; +} + +@ShouldThrow( + 'Expected to find an System environment variable named `MISSING_ENV` for field `missingEnv` but no value was found.', +) +@Envied( + environment: true, + path: 'test/.env.environment', +) +abstract class Env37e { + @EnviedField(varName: 'missing_env') + static final String missingEnv = ''; +} diff --git a/packages/envied_generator/test/src/generator_tests_with_path_override.dart b/packages/envied_generator/test/src/generator_tests_with_path_override.dart index d5effa3..0bca31e 100644 --- a/packages/envied_generator/test/src/generator_tests_with_path_override.dart +++ b/packages/envied_generator/test/src/generator_tests_with_path_override.dart @@ -6,6 +6,7 @@ import 'package:source_gen_test/annotations.dart'; @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example_with_path_override final class _EnvWithPathOverride0 {} ''') @Envied() @@ -14,6 +15,7 @@ abstract class EnvWithPathOverride0 {} @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example_with_path_override final class _EnvWithPathOverride1 {} ''') @Envied(requireEnvFile: true) @@ -22,6 +24,7 @@ abstract class EnvWithPathOverride1 {} @ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint +// generated_from: test/.env.example_with_path_override final class _EnvWithPathOverride2 { static const String foo = 'bar';