blob: 4d3a1514403ea4fef6d6a8df6592bbd9d45292b6 [file] [edit]
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'package:args/args.dart';
import 'package:firehose/src/github.dart';
Future<void> main(List<String> arguments) async {
final parser = _createArgParser();
late final ArgResults results;
try {
results = parser.parse(arguments);
} on ArgParserException catch (e) {
stderr.writeln(e.message);
exitCode = 64;
return;
}
final command = results.command;
if (command == null) {
stderr.writeln('Usage: comment <command> [options]');
stderr.writeln(parser.usage);
stderr.writeln('\nAvailable commands:');
for (final cmd in parser.commands.keys) {
stderr.writeln(' $cmd');
}
exitCode = 64;
return;
}
if (command.name == 'find') {
await _findComment(command);
} else if (command.name == 'create-or-update') {
await _createOrUpdateComment(command);
}
}
ArgParser _createArgParser() {
final parser = ArgParser();
parser.addCommand('find')
..addOption('issue', help: 'PR or issue number', mandatory: true)
..addOption('author',
help: 'Comment author', defaultsTo: 'github-actions[bot]')
..addOption('body-includes', help: 'String to search for in comment body');
parser.addCommand('create-or-update')
..addOption('issue', help: 'PR or issue number')
..addOption('comment-id', help: 'Existing comment ID to update')
..addOption('body', help: 'Comment body text')
..addOption('body-path', help: 'Path to file containing comment body');
return parser;
}
Future<void> _findComment(ArgResults results) async {
final issue = results.option('issue') as String;
final author = results.option('author') as String;
final bodyIncludes = results.option('body-includes');
final issueNumber = int.tryParse(issue);
if (issueNumber == null) {
stderr.writeln('Invalid issue number: $issue');
exitCode = 64;
return;
}
final github = GithubApi(issueNumber: issueNumber);
try {
final commentId = await github.findCommentId(
user: author,
searchTerm: bodyIncludes,
);
if (commentId != null) {
print(commentId);
} else {
print('0');
}
} finally {
github.close();
}
}
Future<void> _createOrUpdateComment(ArgResults results) async {
final issue = results.option('issue');
final commentId = results.option('comment-id');
var body = results.option('body');
final bodyPath = results.option('body-path');
if (bodyPath != null) {
try {
body = await File(bodyPath).readAsString();
} catch (e) {
stderr.writeln('Error reading body-path: $e');
exitCode = 1;
return;
}
}
if (body == null || body.trim().isEmpty) {
stderr.writeln('Comment body cannot be empty');
exitCode = 64;
return;
}
int? issueNumber;
if (issue != null) {
issueNumber = int.tryParse(issue);
if (issueNumber == null) {
stderr.writeln('Invalid issue number: $issue');
exitCode = 64;
return;
}
}
final github = GithubApi(issueNumber: issueNumber);
try {
if (commentId != null && commentId != '0' && commentId.isNotEmpty) {
final id = int.tryParse(commentId);
if (id == null) {
stderr.writeln('Invalid comment ID: $commentId');
exitCode = 64;
return;
}
await github.updateComment(id, body);
print('Updated comment $id');
} else {
final resolvedIssueNumber = github.issueNumber;
if (resolvedIssueNumber == null) {
stderr.writeln('Missing issue number for create');
exitCode = 64;
return;
}
await github.createComment(resolvedIssueNumber, body);
print('Created comment');
}
} finally {
github.close();
}
}