Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,41 @@ Provide the identifier (`id`) of the symbols file (e.g. `--id=2c7a3u3`). You can
raygun-cli symbols delete --id=<id> --app-id=APP_ID --token=TOKEN
```

#### Deployment Tracking

Send deployment tracking notifications to [raygun.com](https://raygun.com).

Documentation: https://raygun.com/documentation/product-guides/deployment-tracking/overview/

Minimal arguments are:

```
raygun-cli depoyments --app-id=APP_ID --token=TOKEN --version=<app version> --api-key=<Raygun app API key>
```

Example outputs:

```
Success:

Success creating deployment: 201
Deployment identifier: 2cewu0m
Deployment created successfully

Missing Access Token:

Error creating deployment: 401
Response: {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.2","title":"Unauthorized","status":401,"traceId":"00-b9f01ba3ff4a938501c760e6924acc81-53e9411804aa9f2f-00"}
Failed to create deployment

Access Token misses access to application:

Error creating deployment: 404
Response: {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.5","title":"Not Found","status":404,"traceId":"00-5c3a2423f922d787e20d01456b6c1836-b88c29232af94db8-00"}
Failed to create deployment

```

## Development

### Compiling a binary
Expand Down
10 changes: 10 additions & 0 deletions bin/raygun_cli.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:args/args.dart';
import 'package:raygun_cli/sourcemap/sourcemap_command.dart';
import 'package:raygun_cli/symbols/flutter_symbols.dart';
import 'package:raygun_cli/deployments/deployments_command.dart';

const String version = '0.0.2';

Expand Down Expand Up @@ -30,6 +31,10 @@ ArgParser buildParser() {
..addCommand(
kSymbolsCommand,
buildParserSymbols(),
)
..addCommand(
kDeploymentsCommand,
buildParserDeployments(),
);
}

Expand Down Expand Up @@ -74,6 +79,11 @@ void main(List<String> arguments) {
return;
}

if (results.command?.name == kDeploymentsCommand) {
parseDeploymentsCommand(results.command!, verbose);
return;
}

if (verbose) {
print('[VERBOSE] All arguments: ${results.arguments}');
}
Expand Down
73 changes: 73 additions & 0 deletions lib/deployments/deployments.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'dart:io';

import 'package:raygun_cli/deployments/deployments_api.dart';
import 'package:args/args.dart';
import '../config_props.dart';

class Deployments {
final ArgResults command;
final bool verbose;
late final String appId;
late final String token;

Deployments({
required this.command,
required this.verbose,
required ConfigProps config,
}) {
appId = config.appId;
token = config.token;
}

Future<void> notify() async {
if (!command.wasParsed('api-key')) {
print('Error: Missing "--api-key"');
print(' Please provide "--api-key" via argument');
exit(2);
}
if (!command.wasParsed('version')) {
print('Error: Missing "--version"');
print(' Please provide "--version" via argument');
exit(2);
}

final apiKey = command.option('api-key') as String;
final version = command.option('version') as String;
final ownerName = command.option('owner-name');
final emailAddress = command.option('email-address');
final comment = command.option('comment');
final scmIdentifier = command.option('scm-identifier');
final scmType = command.option('scm-type');

if (verbose) {
print('app-id: $appId');
print('token: $token');
print('api-key: $apiKey');
print('version: $version');
print('owner-name: $ownerName');
print('email-address: $emailAddress');
print('comment: $comment');
print('scm-identifier: $scmIdentifier');
print('scm-type: $scmType');
}

final success = await createDeployment(
token: token,
apiKey: apiKey,
version: version,
ownerName: ownerName,
emailAddress: emailAddress,
comment: comment,
scmIdentifier: scmIdentifier,
scmType: scmType,
);

if (success) {
print('Deployment created successfully');
exit(0);
} else {
print('Failed to create deployment');
exit(2);
}
}
}
51 changes: 51 additions & 0 deletions lib/deployments/deployments_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<bool> createDeployment({
required String token,
required String apiKey,
required String version,
String? ownerName,
String? emailAddress,
String? comment,
String? scmIdentifier,
String? scmType,
}) async {
final url =
'https://api.raygun.com/v3/applications/api-key/$apiKey/deployments';

final payload = {
'version': version,
if (ownerName != null) 'ownerName': ownerName,
if (emailAddress != null) 'emailAddress': emailAddress,
if (comment != null) 'comment': comment,
if (scmIdentifier != null) 'scmIdentifier': scmIdentifier,
if (scmType != null) 'scmType': scmType,
'deployedAt': DateTime.now().toUtc().toIso8601String(),
};

try {
final response = await http.post(
Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: jsonEncode(payload),
);

if (response.statusCode == 200 || response.statusCode == 201) {
print('Success creating deployment: ${response.statusCode}');
print(
'Deployment identifier: ${jsonDecode(response.body)['identifier']}');
return true;
}

print('Error creating deployment: ${response.statusCode}');
print('Response: ${response.body}');
return false;
} catch (e) {
print('Exception while creating deployment: $e');
return false;
}
}
80 changes: 80 additions & 0 deletions lib/deployments/deployments_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'dart:io';

import 'package:args/args.dart';
import 'package:raygun_cli/deployments/deployments.dart';

import '../config_props.dart';

const kDeploymentsCommand = 'deployments';

ArgParser buildParserDeployments() {
return ArgParser()
..addFlag(
'help',
abbr: 'h',
negatable: false,
help: 'Print deployments usage information',
)
..addOption(
'app-id',
help: 'Raygun application ID',
)
..addOption(
'token',
help: 'Raygun access token',
)
..addOption(
'api-key',
mandatory: true,
help: 'API key from the Raygun account you are deploying to',
)
..addOption(
'version',
mandatory: true,
help:
'Version of the software you are deploying and want Raygun to know about',
)
..addOption(
'scm-type',
mandatory: false,
allowed: ['GitHub', 'Bitbucket', 'GitLab', 'AzureDevOps'],
help:
'Type of the source control management system you are deploying from - if provided, one of [GitHub, Bitbucket, GitLab, AzureDevOps]',
)
..addOption(
'scm-identifier',
mandatory: false,
help: 'Commit that this deployment is based on',
)
..addOption(
'owner-name',
mandatory: false,
help: 'Name of the person deploying the software',
)
..addOption(
'email-address',
mandatory: false,
help: 'Email address of the person deploying the software',
)
..addOption(
'comment',
mandatory: false,
help: 'Deployment comment',
);
}

void parseDeploymentsCommand(ArgResults command, bool verbose) {
if (command.wasParsed('help')) {
print('Usage: raygun-cli deployments <arguments>');
print(buildParserDeployments().usage);
exit(0);
}

final configProps = ConfigProps.load(command, verbose: verbose);

Deployments(
command: command,
verbose: verbose,
config: configProps,
).notify();
}
4 changes: 2 additions & 2 deletions lib/sourcemap/sourcemap_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ ArgParser buildParserSourcemap() {
)
..addOption(
'app-id',
help: 'Raygun\'s application ID',
help: 'Raygun application ID',
)
..addOption(
'token',
help: 'Raygun\'s access token',
help: 'Raygun access token',
)
..addOption(
'platform',
Expand Down
4 changes: 2 additions & 2 deletions lib/symbols/flutter_symbols.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ ArgParser buildParserSymbols() {
)
..addOption(
'app-id',
help: 'Raygun\'s application ID',
help: 'Raygun application ID',
)
..addOption(
'token',
help: 'Raygun\'s access token',
help: 'Raygun access token',
)
..addOption(
'path',
Expand Down
Loading