Skip to content

Commit 18e44eb

Browse files
author
serverpod_cloud
committed
feat: ae41c82172843ec5c504f7172e0916237541d587
1 parent 880c07b commit 18e44eb

16 files changed

Lines changed: 1007 additions & 515 deletions

ground_control_client/lib/src/protocol/client.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,9 +805,11 @@ class EndpointDeploy extends _i1.EndpointRef {
805805
_i2.Future<String> createUploadDescription(
806806
String cloudProjectId, {
807807
String? serverpodVersion,
808+
String? dartVersion,
808809
}) => caller.callServerEndpoint<String>('deploy', 'createUploadDescription', {
809810
'cloudProjectId': cloudProjectId,
810811
'serverpodVersion': serverpodVersion,
812+
'dartVersion': dartVersion,
811813
});
812814
}
813815

ground_control_client/lib/src/protocol/protocol.dart

Lines changed: 155 additions & 134 deletions
Large diffs are not rendered by default.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
2+
/* To generate run: "serverpod generate" */
3+
4+
// ignore_for_file: implementation_imports
5+
// ignore_for_file: library_private_types_in_public_api
6+
// ignore_for_file: non_constant_identifier_names
7+
// ignore_for_file: public_member_api_docs
8+
// ignore_for_file: type_literal_in_constant_pattern
9+
// ignore_for_file: use_super_parameters
10+
// ignore_for_file: invalid_use_of_internal_member
11+
12+
// ignore_for_file: no_leading_underscores_for_library_prefixes
13+
import 'package:serverpod_client/serverpod_client.dart' as _i1;
14+
15+
abstract class DartSdkUnsupportedConstraintException
16+
implements _i1.SerializableException, _i1.SerializableModel {
17+
DartSdkUnsupportedConstraintException._({required this.message});
18+
19+
factory DartSdkUnsupportedConstraintException({required String message}) =
20+
_DartSdkUnsupportedConstraintExceptionImpl;
21+
22+
factory DartSdkUnsupportedConstraintException.fromJson(
23+
Map<String, dynamic> jsonSerialization,
24+
) {
25+
return DartSdkUnsupportedConstraintException(
26+
message: jsonSerialization['message'] as String,
27+
);
28+
}
29+
30+
String message;
31+
32+
/// Returns a shallow copy of this [DartSdkUnsupportedConstraintException]
33+
/// with some or all fields replaced by the given arguments.
34+
@_i1.useResult
35+
DartSdkUnsupportedConstraintException copyWith({String? message});
36+
@override
37+
Map<String, dynamic> toJson() {
38+
return {
39+
'__className__': 'DartSdkUnsupportedConstraintException',
40+
'message': message,
41+
};
42+
}
43+
44+
@override
45+
String toString() {
46+
return 'DartSdkUnsupportedConstraintException(message: $message)';
47+
}
48+
}
49+
50+
class _DartSdkUnsupportedConstraintExceptionImpl
51+
extends DartSdkUnsupportedConstraintException {
52+
_DartSdkUnsupportedConstraintExceptionImpl({required String message})
53+
: super._(message: message);
54+
55+
/// Returns a shallow copy of this [DartSdkUnsupportedConstraintException]
56+
/// with some or all fields replaced by the given arguments.
57+
@_i1.useResult
58+
@override
59+
DartSdkUnsupportedConstraintException copyWith({String? message}) {
60+
return DartSdkUnsupportedConstraintException(
61+
message: message ?? this.message,
62+
);
63+
}
64+
}

serverpod_cloud_cli/lib/commands/deploy/deploy.dart

Lines changed: 131 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import 'dart:io';
22

33
import 'package:dio/dio.dart';
4-
import 'package:ground_control_client/ground_control_client.dart';
4+
import 'package:ground_control_client/ground_control_client.dart'
5+
show
6+
Client,
7+
DartSdkUnsupportedConstraintException,
8+
InvalidValueException,
9+
ServerpodClientException;
510
import 'package:serverpod_cloud_cli/command_logger/command_logger.dart';
611
import 'package:serverpod_cloud_cli/command_runner/helpers/file_uploader_factory.dart';
712
import 'package:serverpod_cloud_cli/commands/deploy/script_runner.dart';
813
import 'package:serverpod_cloud_cli/project_zipper/project_zipper.dart';
914
import 'package:serverpod_cloud_cli/project_zipper/project_zipper_exceptions.dart';
1015
import 'package:serverpod_cloud_cli/shared/exceptions/exit_exceptions.dart';
11-
import 'package:serverpod_cloud_cli/util/dart_version_util.dart';
12-
import 'package:serverpod_cloud_cli/util/pubspec_validator.dart';
16+
import 'package:serverpod_cloud_cli/util/dart_version_util.dart'
17+
show ProjectDartVersionHint;
18+
import 'package:serverpod_cloud_cli/util/pubspec_validator.dart'
19+
show TenantProjectPubspec;
1320
import 'package:serverpod_cloud_cli/util/scloud_config/scloud_config_io.dart';
14-
import 'package:serverpod_cloud_cli/util/scloud_config/scloud_config_model.dart';
1521
import 'package:serverpod_cloud_cli/util/scloudignore.dart' show ScloudIgnore;
22+
import 'package:serverpod_cloud_cli/util/tool_versions_io.dart';
23+
import 'package:serverpod_cloud_cli/util/upload_description_metadata.dart';
1624

1725
import 'prepare_workspace.dart';
1826

@@ -43,7 +51,7 @@ abstract class Deploy {
4351
throw FailureException(errors: issues);
4452
}
4553

46-
var config = ScloudConfigIO.readFromFile(projectConfigFilePath);
54+
final config = ScloudConfigIO.readFromFile(projectConfigFilePath);
4755

4856
if (config != null && config.scripts.preDeploy.isNotEmpty) {
4957
await ScriptRunner.runScripts(
@@ -54,22 +62,74 @@ abstract class Deploy {
5462
);
5563
}
5664

57-
final resolvedDartSdk =
58-
dartVersionOverride ??
59-
config?.dartSdk ??
60-
resolveProjectDartSdkVersion(projectDirectory);
61-
validateDartVersion(resolvedDartSdk);
65+
final dartVersionHint = ProjectDartVersionHint.resolveDartVersionForDeploy(
66+
override: dartVersionOverride,
67+
configDartSdk: config?.dartSdk,
68+
lazyVersionSources: [
69+
() {
70+
final roots = <Directory>[projectDirectory];
71+
if (pubspecValidator.isWorkspaceResolved()) {
72+
final (workspaceRoot, _) = WorkspaceProject.findWorkspaceRoot(
73+
projectDirectory,
74+
);
75+
roots.add(workspaceRoot);
76+
}
77+
return ToolVersionsIO.readDartVersionFromToolVersions(roots);
78+
},
79+
pubspecValidator.environmentSdkConstraint,
80+
],
81+
);
6282

63-
if (resolvedDartSdk != config?.dartSdk) {
64-
config ??= ScloudConfig(
65-
projectId: projectId,
66-
scripts: ScloudScripts.empty(),
67-
);
68-
config = config.copyWith(dartSdk: resolvedDartSdk);
69-
ScloudConfigIO.writeToFile(config, projectConfigFilePath);
70-
}
83+
late final String uploadDescription;
7184

72-
logger.debug('Using Dart SDK version: $resolvedDartSdk');
85+
if (!dryRun) {
86+
final serverpodVersion = pubspecValidator.serverpodVersion;
87+
88+
await logger.progress('Retrieving upload description...', () async {
89+
try {
90+
uploadDescription = await cloudApiClient.deploy
91+
.createUploadDescription(
92+
projectId,
93+
serverpodVersion: serverpodVersion,
94+
dartVersion: dartVersionHint,
95+
);
96+
final resolvedTag = resolvedDartImageTagFromUploadDescription(
97+
uploadDescription,
98+
);
99+
if (resolvedTag != null) {
100+
logger.debug('Using Dart SDK $resolvedTag.');
101+
}
102+
return true;
103+
} on DartSdkUnsupportedConstraintException catch (e) {
104+
throw FailureException(
105+
error: e.message,
106+
hint: 'Please update the constraint and try again.',
107+
);
108+
} on InvalidValueException catch (e) {
109+
throw FailureException(error: e.message);
110+
} on ServerpodClientException catch (e) {
111+
if (e.message.toLowerCase().contains('connection timed out')) {
112+
throw FailureException(
113+
error:
114+
'Connection timed out. Please check your internet connection and try again.',
115+
hint: 'Try increasing the timeout with the --timeout option.',
116+
reason: e.toString(),
117+
);
118+
}
119+
throw FailureException.nested(
120+
e,
121+
null,
122+
'Failed to fetch upload description.',
123+
);
124+
} on Exception catch (e, stackTrace) {
125+
throw FailureException.nested(
126+
e,
127+
stackTrace,
128+
'Failed to fetch upload description.',
129+
);
130+
}
131+
}, newParagraph: true);
132+
}
73133

74134
final Directory rootDirectory;
75135
final Iterable<String> includedSubPaths;
@@ -90,64 +150,60 @@ abstract class Deploy {
90150
}
91151

92152
late final List<int> projectZip;
93-
final isZipped = await logger.progress(
94-
'Zipping project...',
95-
newParagraph: true,
96-
() async {
97-
try {
98-
projectZip = await ProjectZipper.zipProject(
99-
logger: logger,
100-
rootDirectory: rootDirectory,
101-
beneath: includedSubPaths,
102-
fileReadPoolSize: concurrency,
103-
showFiles: showFiles,
104-
fileContentModifier: (final relativePath, final contentReader) async {
105-
final isPubspec =
106-
relativePath.endsWith('pubspec.yaml') &&
107-
!relativePath.contains('.scloud/');
108-
if (isPubspec) {
109-
final content = await contentReader();
110-
return WorkspaceProject.stripDevDependenciesFromPubspecContent(
111-
content,
112-
);
113-
}
114-
return null;
115-
},
116-
);
117-
return true;
118-
} on ProjectZipperExceptions catch (e) {
119-
switch (e) {
120-
case ProjectDirectoryDoesNotExistException():
121-
logger.error('Project directory does not exist: ${e.path}');
122-
break;
123-
case EmptyProjectException():
124-
logger.error(
125-
'No files to upload.',
126-
hint:
127-
'Ensure that the correct project directory is selected (either through the --project-dir flag or the current directory) and check '
128-
'that `.gitignore` and `.scloudignore` does not filter out all project files.',
129-
);
130-
break;
131-
case DirectorySymLinkException():
132-
logger.error(
133-
'Serverpod Cloud does not support directory symlinks: `${e.path}`',
134-
);
135-
break;
136-
case NonResolvingSymlinkException():
137-
logger.error(
138-
'Serverpod Cloud does not support non-resolving symlinks: `${e.path}` => `${e.target}`',
153+
final isZipped = await logger.progress('Zipping project...', () async {
154+
try {
155+
projectZip = await ProjectZipper.zipProject(
156+
logger: logger,
157+
rootDirectory: rootDirectory,
158+
beneath: includedSubPaths,
159+
fileReadPoolSize: concurrency,
160+
showFiles: showFiles,
161+
fileContentModifier: (final relativePath, final contentReader) async {
162+
final isPubspec =
163+
relativePath.endsWith('pubspec.yaml') &&
164+
!relativePath.contains('.scloud/');
165+
if (isPubspec) {
166+
final content = await contentReader();
167+
return WorkspaceProject.stripDevDependenciesFromPubspecContent(
168+
content,
139169
);
140-
break;
141-
case NullZipException():
142-
logger.error(
143-
'Unknown error occurred while zipping project, please try again.',
144-
);
145-
break;
146-
}
147-
return false;
170+
}
171+
return null;
172+
},
173+
);
174+
return true;
175+
} on ProjectZipperExceptions catch (e) {
176+
switch (e) {
177+
case ProjectDirectoryDoesNotExistException():
178+
logger.error('Project directory does not exist: ${e.path}');
179+
break;
180+
case EmptyProjectException():
181+
logger.error(
182+
'No files to upload.',
183+
hint:
184+
'Ensure that the correct project directory is selected (either through the --project-dir flag or the current directory) and check '
185+
'that `.gitignore` and `.scloudignore` does not filter out all project files.',
186+
);
187+
break;
188+
case DirectorySymLinkException():
189+
logger.error(
190+
'Serverpod Cloud does not support directory symlinks: `${e.path}`',
191+
);
192+
break;
193+
case NonResolvingSymlinkException():
194+
logger.error(
195+
'Serverpod Cloud does not support non-resolving symlinks: `${e.path}` => `${e.target}`',
196+
);
197+
break;
198+
case NullZipException():
199+
logger.error(
200+
'Unknown error occurred while zipping project, please try again.',
201+
);
202+
break;
148203
}
149-
},
150-
);
204+
return false;
205+
}
206+
});
151207

152208
if (!isZipped) throw ErrorExitException('Failed to zip project.');
153209

@@ -172,41 +228,6 @@ abstract class Deploy {
172228
return true;
173229
});
174230
} else {
175-
late final String uploadDescription;
176-
177-
final serverpodVersion = pubspecValidator.serverpodVersion;
178-
179-
await logger.progress('Retrieving upload description...', () async {
180-
try {
181-
uploadDescription = await cloudApiClient.deploy
182-
.createUploadDescription(
183-
projectId,
184-
serverpodVersion: serverpodVersion,
185-
);
186-
return true;
187-
} on ServerpodClientException catch (e) {
188-
if (e.message.toLowerCase().contains('connection timed out')) {
189-
throw FailureException(
190-
error:
191-
'Connection timed out. Please check your internet connection and try again.',
192-
hint: 'Try increasing the timeout with the --timeout option.',
193-
reason: e.toString(),
194-
);
195-
}
196-
throw FailureException.nested(
197-
e,
198-
null,
199-
'Failed to fetch upload description.',
200-
);
201-
} on Exception catch (e, stackTrace) {
202-
throw FailureException.nested(
203-
e,
204-
stackTrace,
205-
'Failed to fetch upload description.',
206-
);
207-
}
208-
});
209-
210231
final success = await logger.progress('Uploading project...', () async {
211232
try {
212233
final fileUploader = fileUploaderFactory(uploadDescription);

0 commit comments

Comments
 (0)