@@ -24,20 +24,22 @@ import 'package:serverpod_cloud_cli/command_runner/helpers/cloud_cli_service_pro
2424import 'package:serverpod_cloud_cli/command_runner/helpers/cli_version_checker.dart' ;
2525import 'package:serverpod_cloud_cli/constants.dart' ;
2626import 'package:serverpod_cloud_cli/persistent_storage/resource_manager.dart' ;
27+ import 'package:serverpod_cloud_cli/util/activation_checker.dart' ;
2728import 'package:serverpod_cloud_cli/util/common.dart' ;
2829import 'package:serverpod_cloud_cli/util/pubspec_validator.dart' ;
2930import 'package:serverpod_cloud_cli/util/scloud_config/scloud_config.dart' ;
3031import 'package:serverpod_cloud_cli/util/scloud_version.dart' ;
3132
3233import 'commands/admin/admin_command.dart' ;
34+ import 'commands/settings_command.dart' ;
3335import 'completion/completion_script_carapace.dart' ;
3436import 'completion/completion_script_completely.dart' ;
3537
3638/// Represents the Serverpod Cloud CLI main command, its global options, and subcommands.
3739class CloudCliCommandRunner extends BetterCommandRunner <GlobalOption , void > {
3840 final Version version;
3941 final CommandLogger logger;
40- final CloudCliServiceProvider serviceProvider ;
42+ final CloudCliServiceProvider _serviceProvider ;
4143
4244 final VersionCommand _versionCommand;
4345
@@ -64,12 +66,26 @@ class CloudCliCommandRunner extends BetterCommandRunner<GlobalOption, void> {
6466 logger.configuration = _globalConfiguration;
6567 }
6668
69+ /// Gets the initialized service provider for the Serverpod Cloud CLI.
70+ /// Must not be called before the [run] method has been invoked.
71+ CloudCliServiceProvider get serviceProvider {
72+ if (! _serviceProvider.initialized) {
73+ _serviceProvider.initialize (
74+ globalConfiguration: globalConfiguration,
75+ logger: logger,
76+ );
77+ }
78+ return _serviceProvider;
79+ }
80+
6781 CloudCliCommandRunner ._({
6882 required this .logger,
6983 required this .version,
70- required this .serviceProvider,
84+ required final CloudCliServiceProvider serviceProvider,
85+ super .onAnalyticsEvent,
7186 super .setLogLevel,
72- }) : _versionCommand = VersionCommand (logger: logger),
87+ }) : _serviceProvider = serviceProvider,
88+ _versionCommand = VersionCommand (logger: logger),
7389 super (
7490 'scloud' ,
7591 'Manage your Serverpod Cloud projects' ,
@@ -89,12 +105,14 @@ class CloudCliCommandRunner extends BetterCommandRunner<GlobalOption, void> {
89105 required final CommandLogger logger,
90106 final Version ? version,
91107 final CloudCliServiceProvider ? serviceProvider,
108+ final OnAnalyticsEvent ? onAnalyticsEvent,
92109 bool ? adminUserMode,
93110 }) {
94111 final runner = CloudCliCommandRunner ._(
95112 logger: logger,
96113 version: version ?? cliVersion,
97114 serviceProvider: serviceProvider ?? CloudCliServiceProvider (),
115+ onAnalyticsEvent: onAnalyticsEvent,
98116 setLogLevel: ({
99117 final String ? commandName,
100118 required final CommandRunnerLogLevel parsedLogLevel,
@@ -126,6 +144,7 @@ class CloudCliCommandRunner extends BetterCommandRunner<GlobalOption, void> {
126144 CloudDbCommand (logger: logger),
127145 CloudLaunchCommand (logger: logger),
128146 CloudUserCommand (logger: logger),
147+ CliUserSettingsCommand (logger: logger),
129148 if (adminUserMode) CloudAdminCommand (logger: logger, hidden: false ),
130149 ]);
131150
@@ -134,11 +153,6 @@ class CloudCliCommandRunner extends BetterCommandRunner<GlobalOption, void> {
134153
135154 @override
136155 Future <void > runCommand (final ArgResults topLevelResults) async {
137- serviceProvider.initialize (
138- globalConfiguration: globalConfiguration,
139- logger: logger,
140- );
141-
142156 if (globalConfiguration.version) {
143157 await _versionCommand.run ();
144158 }
@@ -179,6 +193,52 @@ class CloudCliCommandRunner extends BetterCommandRunner<GlobalOption, void> {
179193 }
180194 }
181195
196+ @override
197+ Future <bool > determineAnalyticsSettings () async {
198+ if (onAnalyticsEvent == null ) {
199+ return false ;
200+ }
201+
202+ final analyticsOptionValue = globalConfiguration.analytics;
203+ if (analyticsOptionValue != null ) {
204+ // explicitly set via option for this run
205+ return analyticsOptionValue;
206+ }
207+
208+ if (! _isTenantUser ()) {
209+ return false ;
210+ }
211+
212+ final analyticsEnabled = await _getAnalyticsSetting ();
213+ return analyticsEnabled;
214+ }
215+
216+ Future <bool > _getAnalyticsSetting () async {
217+ final settings = serviceProvider.scloudSettings;
218+ final analyticsEnabled = await settings.enableAnalytics;
219+ if (analyticsEnabled != null ) {
220+ return analyticsEnabled;
221+ }
222+
223+ final confirm = await logger.confirm (
224+ 'Do you agree to sending anonymous command usage analytics to Serverpod?' ,
225+ defaultValue: true ,
226+ );
227+ await settings.setEnableAnalytics (confirm);
228+ return confirm;
229+ }
230+
231+ /// Returns true if the user likely is a production tenant user.
232+ bool _isTenantUser () {
233+ if (! isActivatedFromPub ()) {
234+ return false ;
235+ }
236+ if (globalConfiguration.apiServer != HostConstants .serverpodCloudApi) {
237+ return false ;
238+ }
239+ return true ;
240+ }
241+
182242 @override
183243 String ? get usageFooter =>
184244 '\n See the full documentation at: https://docs.serverpod.cloud/' ;
@@ -300,7 +360,14 @@ Directory _getDefaultStorageDir() {
300360enum GlobalOption <V > implements OptionDefinition <V > {
301361 quiet (BetterCommandRunnerFlags .quietOption),
302362 verbose (BetterCommandRunnerFlags .verboseOption),
303- analytics (BetterCommandRunnerFlags .analyticsOption),
363+
364+ analytics (FlagOption (
365+ argName: BetterCommandRunnerFlags .analytics,
366+ argAbbrev: BetterCommandRunnerFlags .analyticsAbbr,
367+ envName: 'SERVERPOD_CLOUD_COMMAND_ANALYTICS' ,
368+ negatable: true ,
369+ helpText: 'Toggles if analytics data is sent.' ,
370+ )),
304371
305372 version (
306373 FlagOption (
@@ -427,6 +494,8 @@ class GlobalConfiguration extends Configuration<GlobalOption> {
427494
428495 bool get version => value (GlobalOption .version);
429496
497+ bool ? get analytics => optionalValue (GlobalOption .analytics);
498+
430499 Directory get scloudDir => value (GlobalOption .scloudDir);
431500
432501 Directory ? get projectDir => optionalValue (GlobalOption .projectDir);
0 commit comments