Skip to content

Commit

Permalink
feat(globe_cli): Add --logs for globe deploy (#28)
Browse files Browse the repository at this point in the history
* feat(globe_cli): Add --logs for globe deploy

* Update docs/cli/commands/deploy.mdx

Co-authored-by: Mike Diarmid <[email protected]>

* Update docs/cli/commands/deploy.mdx

Co-authored-by: Mike Diarmid <[email protected]>

* Update docs/cli/commands/deploy.mdx

Co-authored-by: Mike Diarmid <[email protected]>

---------

Co-authored-by: Mike Diarmid <[email protected]>
  • Loading branch information
lesnitsky and Salakar authored Dec 21, 2023
1 parent 6044060 commit 479b11e
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 86 deletions.
9 changes: 9 additions & 0 deletions docs/cli/commands/deploy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,17 @@ When successfully built, the deployment will be promoted to production and will

You can learn more about [preview and production deployments](/deployments) in the deployments documentation.

### Build logs

If you want to see realtime build logs for your deployment on the CLI, use the `--logs` flag:

```bash
globe deploy --logs
```

### Flags

The command has flags (in addition to [global flags](/cli#global-flags)) that can be used to modify the behavior of the command, which can be accessed by running `globe deploy --<flag>`:

- `--prod` - Creates a deployment that will be promoted to production once built.
- `--logs` - Streams build logs.
181 changes: 95 additions & 86 deletions packages/globe_cli/lib/src/commands/deploy_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:mason_logger/mason_logger.dart';
import '../command.dart';
import '../utils/api.dart';
import '../utils/archiver.dart';
import '../utils/logs.dart';
import '../utils/prompts.dart';

/// `globe deploy`
Expand All @@ -16,11 +17,16 @@ import '../utils/prompts.dart';
class DeployCommand extends BaseGlobeCommand {
/// {@macro deploy_command}
DeployCommand() {
argParser.addFlag(
'prod',
help: 'Creates a new deployment, '
'and if successful promotes it to the latest production deployment.',
);
argParser
..addFlag(
'prod',
help: 'Creates a new deployment, '
'and if successful promotes it to the latest production deployment.',
)
..addFlag(
'logs',
help: 'Shows build logs for the deployment.',
);
}

@override
Expand Down Expand Up @@ -72,87 +78,90 @@ class DeployCommand extends BaseGlobeCommand {
'🔍 View deployment: ${metadata.endpoint}/${validated.organization.slug}/${validated.project.slug}/deployments/${deployment.id}',
);

// TODO: handle deployment logs - they currently disconnect immediately
// var status = logger.progress(deployment.state.message);
// final completer = Completer<void>();
// Stream<BuildLogEvent>? logs;

// // Check the deployment status every x seconds.
// Timer.periodic(const Duration(milliseconds: 2000), (timer) async {
// final update = await api.getDeployment(
// orgId: validated.organization.id,
// projectId: validated.project.id,
// deploymentId: deployment.id,
// );

// if (update.state == DeploymentState.working ||
// update.state == DeploymentState.deploying) {
// if (logs != null) return;

// status.complete();
// status = logger.progress('Preparing build environment');

// logs = await streamBuildLogs(
// api: api,
// orgId: validated.organization.id,
// projectId: validated.project.id,
// deploymentId: deployment.id,
// );

// unawaited(
// logs!
// .firstWhere((element) => element is! UnknownBuildLogEvent)
// .then((_) => status.complete()),
// );

// unawaited(
// logs!.firstWhere((element) {
// if (element case LogsBuildLogEvent(done: final done)) return done;
// return false;
// }).then((_) {
// status = logger.progress('Deploying...');
// }),
// );

// unawaited(printLogs(logger, logs!));
// }

// if (update.state == DeploymentState.success) {
// status.complete();
// logger.info(
// '${lightGreen.wrap('✓')} Preview: https://${update.url}',
// );
// }

// if (update.state == DeploymentState.error) {
// var message = 'Deployment failed';
// if (update.message.isNotEmpty) {
// message = '$message: ${update.message}';
// }
// status.fail(message);
// }

// if (update.state == DeploymentState.cancelled) {
// status.complete();
// logger.info('Deployment cancelled');
// }

// if (update.state == DeploymentState.invalid) {
// status.complete();
// status = logger.progress(
// 'Invalid Deployment State Received. Waiting for valid state',
// );
// }

// if (update.state == DeploymentState.success ||
// update.state == DeploymentState.cancelled ||
// update.state == DeploymentState.error) {
// timer.cancel();
// completer.complete();
// }
// });

// await completer.future;
if (!(argResults!['logs'] as bool)) {
return ExitCode.success.code;
}

var status = logger.progress(deployment.state.message);
final completer = Completer<void>();
Stream<BuildLogEvent>? logs;

// Check the deployment status every x seconds.
Timer.periodic(const Duration(milliseconds: 2000), (timer) async {
final update = await api.getDeployment(
orgId: validated.organization.id,
projectId: validated.project.id,
deploymentId: deployment.id,
);

if (update.state == DeploymentState.working ||
update.state == DeploymentState.deploying) {
if (logs != null) return;

status.complete();
status = logger.progress('Preparing build environment');

logs = await streamBuildLogs(
api: api,
orgId: validated.organization.id,
projectId: validated.project.id,
deploymentId: deployment.id,
);

unawaited(
logs!
.firstWhere((element) => element is! UnknownBuildLogEvent)
.then((_) => status.complete()),
);

unawaited(
logs!.firstWhere((element) {
if (element case LogsBuildLogEvent(done: final done)) return done;
return false;
}).then((_) {
status = logger.progress('Deploying...');
}),
);

unawaited(printLogs(logger, logs!));
}

if (update.state == DeploymentState.success) {
status.complete();
logger.info(
'${lightGreen.wrap('✓')} Preview: https://${update.url}',
);
}

if (update.state == DeploymentState.error) {
var message = 'Deployment failed';
if (update.message.isNotEmpty) {
message = '$message: ${update.message}';
}
status.fail(message);
}

if (update.state == DeploymentState.cancelled) {
status.complete();
logger.info('Deployment cancelled');
}

if (update.state == DeploymentState.invalid) {
status.complete();
status = logger.progress(
'Invalid Deployment State Received. Waiting for valid state',
);
}

if (update.state == DeploymentState.success ||
update.state == DeploymentState.cancelled ||
update.state == DeploymentState.error) {
timer.cancel();
completer.complete();
}
});

await completer.future;

return ExitCode.success.code;
} on ApiException catch (e) {
Expand Down

0 comments on commit 479b11e

Please sign in to comment.