Skip to content

Commit 512664b

Browse files
committed
Feature and documentation
1 parent bb9be4e commit 512664b

File tree

7 files changed

+220
-1
lines changed

7 files changed

+220
-1
lines changed

AGENT.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
## Architecture
1414
- **CLI Tool**: Uploads sourcemaps, manages obfuscation symbols, tracks deployments for Raygun.com
1515
- **Main Entry**: `bin/raygun_cli.dart` - CLI argument parsing and command routing
16-
- **Commands**: `lib/src/` - Four main command modules: sourcemap, symbols, deployments, proguard
16+
- **Commands**: `lib/src/` - Five main command modules: sourcemap, symbols, deployments, proguard, dsym
1717
- **APIs**: Each command has corresponding API client (`*_api.dart`) for Raygun REST API calls
1818
- **Config**: `config_props.dart` handles arg parsing with env var fallbacks (RAYGUN_APP_ID, RAYGUN_TOKEN, RAYGUN_API_KEY)
1919

@@ -311,6 +311,12 @@ dart run bin/raygun_cli.dart proguard \
311311
--path=mapping.txt \
312312
--external-access-token=EAT \
313313
--overwrite
314+
315+
# iOS dSYM upload
316+
dart run bin/raygun_cli.dart dsym \
317+
--app-id=XXX \
318+
--path=path/to/dsym.zip \
319+
--external-access-token=EAT
314320
```
315321

316322
### Environment Variables

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,44 @@ Response:
152152
153153
```
154154

155+
#### iOS dSYM Uploader
156+
157+
Upload dSYM files for iOS to [raygun.com](https://raygun.com).
158+
159+
Documentation: https://raygun.com/documentation/language-guides/apple/crash-reporting/advanced-setup/#symbolication
160+
161+
```
162+
raygun-cli dsym <arguments>
163+
```
164+
165+
Minimal required arguments are:
166+
167+
```
168+
raygun-cli dsym --app-id=APP_ID --path=<Path to dSYM zip file> --external-access-token=<EAT from your Raygun user account settings>
169+
```
170+
171+
Example outputs:
172+
173+
```
174+
Success:
175+
176+
Uploading: <somewhere>/app.dSYM.zip
177+
Success uploading dSYM file: 200
178+
Result: {"Status":"Success","Message":"dSYM files uploaded"}
179+
180+
Wrong External Access Token:
181+
182+
Uploading: <somewhere>/app.dSYM.zip
183+
Error uploading dSYM file: 302
184+
Response:
185+
186+
Invalid dSYM file:
187+
188+
Uploading: <somewhere>/invalid.zip
189+
Success uploading dSYM file: 200
190+
Result: {"Status":"Failure","Message":"No dSYM file found"}
191+
```
192+
155193
#### Flutter obfuscation symbols
156194

157195
Manages obfuscation symbols to [raygun.com](https://raygun.com).

bin/raygun_cli.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ ArgParser buildParser() {
3737
..addCommand(
3838
proguardCommand.name,
3939
proguardCommand.buildParser(),
40+
)
41+
..addCommand(
42+
dsymCommand.name,
43+
dsymCommand.buildParser(),
4044
);
4145
}
4246

@@ -95,6 +99,11 @@ void main(List<String> arguments) {
9599
return;
96100
}
97101

102+
if (results.command?.name == dsymCommand.name) {
103+
dsymCommand.execute(results.command!, verbose);
104+
return;
105+
}
106+
98107
throw FormatException('Unknown or missing command.');
99108
} on FormatException catch (e) {
100109
// Print usage information if an invalid argument was provided.

lib/raygun_cli.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export 'src/deployments/deployments_command.dart';
2+
export 'src/dsym/dsym_command.dart';
23
export 'src/proguard/proguard_command.dart';
34
export 'src/sourcemap/sourcemap_command.dart';
45
export 'src/symbols/symbols_command.dart';

lib/src/dsym/dsym.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import 'package:raygun_cli/src/dsym/dsym_api.dart';
2+
import 'package:args/args.dart';
3+
import '../config_props.dart';
4+
5+
class Dsym {
6+
final ArgResults command;
7+
final bool verbose;
8+
final DsymApi api;
9+
10+
Dsym({
11+
required this.command,
12+
required this.verbose,
13+
required this.api,
14+
});
15+
16+
Future<bool> upload() async {
17+
if (!command.wasParsed('path')) {
18+
print('Error: Missing "--path"');
19+
print(' Please provide "--path" via argument');
20+
return false;
21+
}
22+
23+
if (!command.wasParsed('external-access-token')) {
24+
print('Error: Missing "--external-access-token"');
25+
print(' Please provide "--external-access-token" via argument');
26+
return false;
27+
}
28+
29+
final externalAccessToken =
30+
command.option('external-access-token') as String;
31+
final path = command.option('path') as String;
32+
final appId = ConfigProp.appId.load(command);
33+
34+
if (verbose) {
35+
print('app-id: $appId');
36+
print('external-access-token: $externalAccessToken');
37+
print('path: $path');
38+
}
39+
40+
final success = await api.uploadDsym(
41+
appId: appId,
42+
externalAccessToken: externalAccessToken,
43+
path: path,
44+
);
45+
46+
return success;
47+
}
48+
}

lib/src/dsym/dsym_api.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import 'dart:io';
2+
3+
import 'package:http/http.dart' as http;
4+
import 'package:raygun_cli/src/core/raygun_api.dart';
5+
6+
class DsymApi {
7+
const DsymApi(this.httpClient);
8+
9+
final http.Client httpClient;
10+
11+
DsymApi.create() : httpClient = http.Client();
12+
13+
/// Uploads a dSYM zip file to Raygun.
14+
/// Returns true if the upload was successful.
15+
Future<bool> uploadDsym({
16+
required String appId,
17+
required String externalAccessToken,
18+
required String path,
19+
}) async {
20+
final file = File(path);
21+
if (!file.existsSync()) {
22+
print('$path: file not found!');
23+
return false;
24+
}
25+
print('Uploading: $path');
26+
27+
final request = RaygunMultipartRequestBuilder(
28+
'https://app.raygun.com/dashboard/$appId/settings/symbols?authToken=$externalAccessToken',
29+
'POST',
30+
).addFile('DsymFile', path).build();
31+
32+
try {
33+
final response = await httpClient.send(request);
34+
final responseBody = await response.stream.bytesToString();
35+
36+
if (response.statusCode == 200) {
37+
print('Success uploading dSYM file: ${response.statusCode}');
38+
print('Result: $responseBody');
39+
return true;
40+
}
41+
42+
print('Error uploading dSYM file: ${response.statusCode}');
43+
print('Response: $responseBody');
44+
return false;
45+
} catch (e) {
46+
print('Exception while uploading dSYM file: $e');
47+
return false;
48+
}
49+
}
50+
}

lib/src/dsym/dsym_command.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import 'dart:io';
2+
3+
import 'package:args/args.dart';
4+
import 'package:raygun_cli/src/core/raygun_command.dart';
5+
import 'package:raygun_cli/src/dsym/dsym.dart';
6+
import 'package:raygun_cli/src/dsym/dsym_api.dart';
7+
8+
final DsymCommand dsymCommand = DsymCommand(api: DsymApi.create());
9+
10+
class DsymCommand extends RaygunCommand {
11+
const DsymCommand({required this.api});
12+
13+
final DsymApi api;
14+
15+
@override
16+
String get name => 'dsym';
17+
18+
@override
19+
ArgParser buildParser() {
20+
return ArgParser()
21+
..addFlag(
22+
'help',
23+
abbr: 'h',
24+
negatable: false,
25+
help: 'Print dsym usage information',
26+
)
27+
..addOption(
28+
'app-id',
29+
mandatory: true,
30+
help: 'Raygun application ID',
31+
)
32+
..addOption(
33+
'external-access-token',
34+
mandatory: true,
35+
help: 'Raygun external access token',
36+
)
37+
..addOption(
38+
'path',
39+
mandatory: true,
40+
help: 'Path to the dSYM zip file',
41+
);
42+
}
43+
44+
@override
45+
void execute(ArgResults command, bool verbose) {
46+
if (command.wasParsed('help')) {
47+
print('Usage: raygun-cli $name <arguments>');
48+
print(buildParser().usage);
49+
exit(0);
50+
}
51+
52+
Dsym(
53+
command: command,
54+
verbose: verbose,
55+
api: api,
56+
).upload().then((success) {
57+
if (success) {
58+
exit(0);
59+
} else {
60+
exit(1);
61+
}
62+
}).catchError((error) {
63+
print('Error uploading dSYM file: $error');
64+
exit(2);
65+
});
66+
}
67+
}

0 commit comments

Comments
 (0)