forked from bkinnightskytw/code_work_spawner
chore: cleanup deprecated `IssueAssistantEventSourceDocument`
This commit is contained in:
parent
34330d9b7a
commit
0fb68c886b
|
|
@ -4,4 +4,4 @@
|
|||
run `pnpx skills experimental_install`, `lefthook install` before development at first time.
|
||||
- For any new or modified Dart test under `test/`, use the repo-local skill `dart-gherkin-tests`.
|
||||
- For file more than 500 lines, consider to split it into multiple files for better maintainability.
|
||||
- Keep refactoring e.g. `SOLID` principles
|
||||
- Keep refactoring e.g. `SOLID` principles. Aggresively remove deprecated code and features. Don't be afraid to break backward compatibility.
|
||||
|
|
|
|||
|
|
@ -3,16 +3,15 @@
|
|||
The repo uses an Agent Orchestrator style YAML config with `defaults` and `projects`.
|
||||
|
||||
Project entries can override `issueAssistant` fields when a repo needs a
|
||||
different prompt, mention triggers, responder chain, notification list, or
|
||||
event source.
|
||||
different prompt, mention triggers, responder chain, or notification list.
|
||||
|
||||
Each project also has separate tracker and SCM config. `issueTracker.provider`
|
||||
selects the logical tracker family, `issueTracker.eventSource.type` selects the
|
||||
concrete adapter used to receive updates, and `scm.provider` selects how
|
||||
temporary repo workspaces are prepared for responders. Legacy top-level project
|
||||
`provider` and legacy `issueAssistant.eventSource` are still accepted during
|
||||
load for backward compatibility. When `scm` is omitted it defaults to a
|
||||
matching provider for existing GitHub, GitLab, and Gitea configs.
|
||||
`provider` is still accepted during load for backward compatibility. When `scm` is
|
||||
omitted it defaults to a matching provider for existing GitHub, GitLab, and
|
||||
Gitea configs.
|
||||
|
||||
GitHub projects default to `gh/polling`, GitLab projects default to
|
||||
`glab/polling`, and Gitea projects default to `tea/polling`. OpenProject
|
||||
|
|
|
|||
|
|
@ -142,10 +142,6 @@ class AppConfig {
|
|||
defaults: AppConfigDefaultsDocument(
|
||||
issueAssistant: IssueAssistantConfigDocument(
|
||||
enabled: true,
|
||||
eventSource: IssueAssistantEventSourceDocument(
|
||||
type: IssueTrackerEventSourceKind.ghPolling,
|
||||
pollInterval: '30s',
|
||||
),
|
||||
maxConcurrentIssues: 3,
|
||||
maxResponsesAfterHuman: 1,
|
||||
mentionTriggers: const ['@codex', '@helper'],
|
||||
|
|
@ -155,6 +151,10 @@ class AppConfig {
|
|||
'sample': ProjectConfigDocument(
|
||||
issueTracker: IssueTrackerConfigDocument(
|
||||
provider: IssueTrackerProvider.github,
|
||||
eventSource: EventSourceDocument(
|
||||
type: IssueTrackerEventSourceKind.ghPolling,
|
||||
pollInterval: '30s',
|
||||
),
|
||||
),
|
||||
scm: ScmConfigDocument(provider: ScmProvider.github),
|
||||
repo: 'owner/repo',
|
||||
|
|
@ -207,15 +207,12 @@ class ProjectConfig {
|
|||
);
|
||||
}
|
||||
|
||||
final resolvedIssueAssistantDocument =
|
||||
_resolveProjectIssueAssistantDocument(
|
||||
key: key,
|
||||
issueTracker: document.issueTracker,
|
||||
issueAssistant: document.issueAssistant,
|
||||
final eventSourceDocument = document.issueTracker?.eventSource;
|
||||
final hasExplicitEventSourceType = eventSourceDocument?.type != null;
|
||||
var issueAssistant = defaultAssistant.merge(
|
||||
document.issueAssistant,
|
||||
eventSourceOverlay: eventSourceDocument,
|
||||
);
|
||||
final hasExplicitEventSourceType =
|
||||
resolvedIssueAssistantDocument?.eventSource?.type != null;
|
||||
var issueAssistant = defaultAssistant.merge(resolvedIssueAssistantDocument);
|
||||
final configuredProvider =
|
||||
document.issueTracker?.provider ?? document.provider;
|
||||
final inferredProvider = _issueTrackerProviderForEventSource(
|
||||
|
|
@ -225,7 +222,7 @@ class ProjectConfig {
|
|||
configuredProvider != null &&
|
||||
configuredProvider != inferredProvider) {
|
||||
throw FormatException(
|
||||
'projects.$key.issueAssistant.eventSource '
|
||||
'projects.$key.issueTracker.eventSource '
|
||||
'${_eventSourceConfigValue(issueAssistant.eventSource.type)} '
|
||||
'implies issue tracker provider ${inferredProvider.name}, '
|
||||
'but the legacy configured provider is ${configuredProvider.name}.',
|
||||
|
|
@ -329,50 +326,6 @@ class ProjectConfig {
|
|||
}
|
||||
}
|
||||
|
||||
IssueAssistantConfigDocument? _resolveProjectIssueAssistantDocument({
|
||||
required String key,
|
||||
required IssueTrackerConfigDocument? issueTracker,
|
||||
required IssueAssistantConfigDocument? issueAssistant,
|
||||
}) {
|
||||
final trackerEventSource = issueTracker?.eventSource;
|
||||
final assistantEventSource = issueAssistant?.eventSource;
|
||||
if (trackerEventSource != null &&
|
||||
assistantEventSource != null &&
|
||||
!_eventSourceDocumentsMatch(trackerEventSource, assistantEventSource)) {
|
||||
throw FormatException(
|
||||
'projects.$key.issueTracker.eventSource and '
|
||||
'projects.$key.issueAssistant.eventSource must match when both are set.',
|
||||
);
|
||||
}
|
||||
if (trackerEventSource == null) {
|
||||
return issueAssistant;
|
||||
}
|
||||
return IssueAssistantConfigDocument(
|
||||
enabled: issueAssistant?.enabled,
|
||||
eventSource: trackerEventSource,
|
||||
maxConcurrentIssues: issueAssistant?.maxConcurrentIssues,
|
||||
maxResponsesAfterHuman: issueAssistant?.maxResponsesAfterHuman,
|
||||
mentionTriggers: issueAssistant?.mentionTriggers,
|
||||
prompt: issueAssistant?.prompt,
|
||||
responders: issueAssistant?.responders,
|
||||
capabilities: issueAssistant?.capabilities,
|
||||
notifications: issueAssistant?.notifications,
|
||||
commentTag: issueAssistant?.commentTag,
|
||||
commentPrefixTemplate: issueAssistant?.commentPrefixTemplate,
|
||||
commentFooterTemplate: issueAssistant?.commentFooterTemplate,
|
||||
);
|
||||
}
|
||||
|
||||
bool _eventSourceDocumentsMatch(
|
||||
IssueAssistantEventSourceDocument left,
|
||||
IssueAssistantEventSourceDocument right,
|
||||
) {
|
||||
return left.type == right.type &&
|
||||
left.pollInterval == right.pollInterval &&
|
||||
left.reconciliation == right.reconciliation &&
|
||||
left.reconcileInterval == right.reconcileInterval;
|
||||
}
|
||||
|
||||
class ScmConfig {
|
||||
const ScmConfig({required this.provider});
|
||||
|
||||
|
|
@ -423,14 +376,18 @@ class IssueAssistantConfig {
|
|||
IssueAssistantConfigDocument? document,
|
||||
) {
|
||||
return const _IssueAssistantConfigResolver()
|
||||
.resolve(base: null, overlay: null)
|
||||
.resolve(base: null, overlay: null, eventSourceOverlay: null)
|
||||
.merge(document);
|
||||
}
|
||||
|
||||
IssueAssistantConfig merge(IssueAssistantConfigDocument? overlay) {
|
||||
IssueAssistantConfig merge(
|
||||
IssueAssistantConfigDocument? overlay, {
|
||||
EventSourceDocument? eventSourceOverlay,
|
||||
}) {
|
||||
return const _IssueAssistantConfigResolver().resolve(
|
||||
base: this,
|
||||
overlay: overlay,
|
||||
eventSourceOverlay: eventSourceOverlay,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -589,6 +546,7 @@ class _IssueAssistantConfigResolver {
|
|||
IssueAssistantConfig resolve({
|
||||
required IssueAssistantConfig? base,
|
||||
required IssueAssistantConfigDocument? overlay,
|
||||
required EventSourceDocument? eventSourceOverlay,
|
||||
}) {
|
||||
final responders = overlay?.responders;
|
||||
final notifications = overlay?.notifications;
|
||||
|
|
@ -596,7 +554,7 @@ class _IssueAssistantConfigResolver {
|
|||
enabled: overlay?.enabled ?? base?.enabled ?? true,
|
||||
eventSource: _resolveEventSource(
|
||||
base: base?.eventSource,
|
||||
overlay: overlay?.eventSource,
|
||||
overlay: eventSourceOverlay,
|
||||
),
|
||||
maxConcurrentIssues: _resolvePositiveInt(
|
||||
value: overlay?.maxConcurrentIssues,
|
||||
|
|
@ -643,7 +601,7 @@ class _IssueAssistantConfigResolver {
|
|||
|
||||
IssueEventSourceConfig _resolveEventSource({
|
||||
required IssueEventSourceConfig? base,
|
||||
required IssueAssistantEventSourceDocument? overlay,
|
||||
required EventSourceDocument? overlay,
|
||||
}) {
|
||||
final type =
|
||||
overlay?.type ?? base?.type ?? IssueTrackerEventSourceKind.ghPolling;
|
||||
|
|
@ -873,13 +831,6 @@ void _assertCamelCaseConfigKeys(Map<String, dynamic> root) {
|
|||
final issueAssistant = defaults['issueAssistant'];
|
||||
if (issueAssistant is Map<String, dynamic>) {
|
||||
_assertCamelCaseMap(issueAssistant, scope: 'defaults.issueAssistant');
|
||||
final eventSource = issueAssistant['eventSource'];
|
||||
if (eventSource is Map<String, dynamic>) {
|
||||
_assertCamelCaseMap(
|
||||
eventSource,
|
||||
scope: 'defaults.issueAssistant.eventSource',
|
||||
);
|
||||
}
|
||||
final responders = issueAssistant['responders'];
|
||||
if (responders is List) {
|
||||
for (final responder in responders) {
|
||||
|
|
@ -937,13 +888,6 @@ void _assertCamelCaseConfigKeys(Map<String, dynamic> root) {
|
|||
issueAssistant,
|
||||
scope: 'projects.${entry.key}.issueAssistant',
|
||||
);
|
||||
final eventSource = issueAssistant['eventSource'];
|
||||
if (eventSource is Map<String, dynamic>) {
|
||||
_assertCamelCaseMap(
|
||||
eventSource,
|
||||
scope: 'projects.${entry.key}.issueAssistant.eventSource',
|
||||
);
|
||||
}
|
||||
final responders = issueAssistant['responders'];
|
||||
if (responders is List) {
|
||||
for (final responder in responders) {
|
||||
|
|
@ -996,6 +940,15 @@ IssueTrackerProvider _issueTrackerProviderForEventSource(
|
|||
}
|
||||
|
||||
void _normalizeLegacyEventSourceConfig(Map<String, dynamic> root) {
|
||||
IssueTrackerEventSourceKind providerDefaultEventSourceType(String? provider) {
|
||||
return switch (provider) {
|
||||
'gitlab' => IssueTrackerEventSourceKind.glabPolling,
|
||||
'gitea' => IssueTrackerEventSourceKind.teaPolling,
|
||||
'openproject' => IssueTrackerEventSourceKind.opPolling,
|
||||
_ => IssueTrackerEventSourceKind.ghPolling,
|
||||
};
|
||||
}
|
||||
|
||||
void normalizeProjectTracker(Map<String, dynamic> project) {
|
||||
final repo = project['repo'];
|
||||
if (repo != null && repo is! String) {
|
||||
|
|
@ -1040,58 +993,6 @@ void _normalizeLegacyEventSourceConfig(Map<String, dynamic> root) {
|
|||
issueTracker['eventSource'] = normalizedEventSource;
|
||||
}
|
||||
|
||||
void normalizeIssueAssistant(
|
||||
Map<String, dynamic> issueAssistant, {
|
||||
required IssueTrackerEventSourceKind? defaultType,
|
||||
}) {
|
||||
final rawEventSource = issueAssistant['eventSource'];
|
||||
Map<String, dynamic>? normalizedEventSource;
|
||||
|
||||
if (rawEventSource is String) {
|
||||
normalizedEventSource = <String, dynamic>{'type': rawEventSource};
|
||||
} else if (rawEventSource is Map<String, dynamic>) {
|
||||
normalizedEventSource = Map<String, dynamic>.from(rawEventSource);
|
||||
} else if (rawEventSource == null) {
|
||||
if (issueAssistant.containsKey('pollInterval') ||
|
||||
issueAssistant.containsKey('reconciliation') ||
|
||||
issueAssistant.containsKey('reconcileInterval')) {
|
||||
normalizedEventSource = <String, dynamic>{};
|
||||
}
|
||||
}
|
||||
|
||||
if (normalizedEventSource == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defaultType != null && !normalizedEventSource.containsKey('type')) {
|
||||
normalizedEventSource['type'] = _eventSourceConfigValue(defaultType);
|
||||
}
|
||||
|
||||
for (final field in [
|
||||
'pollInterval',
|
||||
'reconciliation',
|
||||
'reconcileInterval',
|
||||
]) {
|
||||
if (issueAssistant.containsKey(field) &&
|
||||
!normalizedEventSource.containsKey(field)) {
|
||||
normalizedEventSource[field] = issueAssistant.remove(field);
|
||||
}
|
||||
}
|
||||
|
||||
issueAssistant['eventSource'] = normalizedEventSource;
|
||||
}
|
||||
|
||||
final defaults = root['defaults'];
|
||||
if (defaults is Map<String, dynamic>) {
|
||||
final issueAssistant = defaults['issueAssistant'];
|
||||
if (issueAssistant is Map<String, dynamic>) {
|
||||
normalizeIssueAssistant(
|
||||
issueAssistant,
|
||||
defaultType: IssueTrackerEventSourceKind.ghPolling,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final projects = root['projects'];
|
||||
if (projects is Map<String, dynamic>) {
|
||||
for (final entry in projects.entries) {
|
||||
|
|
@ -1101,45 +1002,15 @@ void _normalizeLegacyEventSourceConfig(Map<String, dynamic> root) {
|
|||
}
|
||||
normalizeProjectTracker(project);
|
||||
final issueTracker = project['issueTracker'];
|
||||
final projectDefaultType = providerDefaultEventSourceType(
|
||||
(project['issueTracker'] as Map<String, dynamic>?)?['provider']
|
||||
as String? ??
|
||||
project['provider'] as String?,
|
||||
);
|
||||
if (issueTracker is Map<String, dynamic>) {
|
||||
normalizeIssueTrackerEventSource(
|
||||
issueTracker,
|
||||
defaultType: switch (issueTracker['provider'] as String?) {
|
||||
'gitlab' => IssueTrackerEventSourceKind.glabPolling,
|
||||
'gitea' => IssueTrackerEventSourceKind.teaPolling,
|
||||
'openproject' => IssueTrackerEventSourceKind.opPolling,
|
||||
_ => IssueTrackerEventSourceKind.ghPolling,
|
||||
},
|
||||
);
|
||||
}
|
||||
final issueAssistant = project['issueAssistant'];
|
||||
if (issueAssistant is! Map<String, dynamic>) {
|
||||
if (issueTracker is Map<String, dynamic> &&
|
||||
issueTracker['eventSource'] is Map<String, dynamic>) {
|
||||
project['issueAssistant'] = <String, dynamic>{
|
||||
'eventSource': Map<String, dynamic>.from(
|
||||
issueTracker['eventSource'] as Map<String, dynamic>,
|
||||
),
|
||||
};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
normalizeIssueAssistant(
|
||||
issueAssistant,
|
||||
defaultType: switch ((project['issueTracker']
|
||||
as Map<String, dynamic>?)?['provider']
|
||||
as String?) {
|
||||
'gitlab' => IssueTrackerEventSourceKind.glabPolling,
|
||||
'gitea' => IssueTrackerEventSourceKind.teaPolling,
|
||||
'openproject' => IssueTrackerEventSourceKind.opPolling,
|
||||
_ => IssueTrackerEventSourceKind.ghPolling,
|
||||
},
|
||||
);
|
||||
if (issueTracker is Map<String, dynamic> &&
|
||||
issueTracker['eventSource'] == null &&
|
||||
issueAssistant['eventSource'] is Map<String, dynamic>) {
|
||||
issueTracker['eventSource'] = Map<String, dynamic>.from(
|
||||
issueAssistant['eventSource'] as Map<String, dynamic>,
|
||||
defaultType: projectDefaultType,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class IssueTrackerConfigDocument {
|
|||
const IssueTrackerConfigDocument({this.provider, this.eventSource});
|
||||
|
||||
final IssueTrackerProvider? provider;
|
||||
final IssueAssistantEventSourceDocument? eventSource;
|
||||
final EventSourceDocument? eventSource;
|
||||
|
||||
factory IssueTrackerConfigDocument.fromJson(Map<String, dynamic> json) =>
|
||||
_$IssueTrackerConfigDocumentFromJson(json);
|
||||
|
|
@ -127,7 +127,6 @@ class ScmConfigDocument {
|
|||
class IssueAssistantConfigDocument {
|
||||
const IssueAssistantConfigDocument({
|
||||
this.enabled,
|
||||
this.eventSource,
|
||||
this.maxConcurrentIssues,
|
||||
this.maxResponsesAfterHuman,
|
||||
this.mentionTriggers,
|
||||
|
|
@ -141,7 +140,6 @@ class IssueAssistantConfigDocument {
|
|||
});
|
||||
|
||||
final bool? enabled;
|
||||
final IssueAssistantEventSourceDocument? eventSource;
|
||||
final int? maxConcurrentIssues;
|
||||
final int? maxResponsesAfterHuman;
|
||||
final List<String>? mentionTriggers;
|
||||
|
|
@ -166,8 +164,8 @@ class IssueAssistantConfigDocument {
|
|||
explicitToJson: true,
|
||||
includeIfNull: false,
|
||||
)
|
||||
class IssueAssistantEventSourceDocument {
|
||||
const IssueAssistantEventSourceDocument({
|
||||
class EventSourceDocument {
|
||||
const EventSourceDocument({
|
||||
this.type,
|
||||
this.pollInterval,
|
||||
this.reconciliation,
|
||||
|
|
@ -179,12 +177,10 @@ class IssueAssistantEventSourceDocument {
|
|||
final IssueTrackerReconciliationKind? reconciliation;
|
||||
final String? reconcileInterval;
|
||||
|
||||
factory IssueAssistantEventSourceDocument.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$IssueAssistantEventSourceDocumentFromJson(json);
|
||||
factory EventSourceDocument.fromJson(Map<String, dynamic> json) =>
|
||||
_$EventSourceDocumentFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$IssueAssistantEventSourceDocumentToJson(this);
|
||||
Map<String, dynamic> toJson() => _$EventSourceDocumentToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ void main() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
maxResponsesAfterHuman: 2
|
||||
mentionTriggers: ["@helper"]
|
||||
prompt: "default {{repo}}"
|
||||
|
|
@ -723,7 +722,7 @@ projects:
|
|||
/// ```gherkin
|
||||
/// Scenario: Keep the legacy issue tracker provider as a fallback
|
||||
/// Given a config whose project still sets issueTracker.provider to gitea
|
||||
/// And the project omits issueAssistant.eventSource.type
|
||||
/// And the project omits issueTracker.eventSource.type
|
||||
/// When loading the app config from disk
|
||||
/// Then the project keeps the configured Gitea provider
|
||||
/// And the polling event source is rewritten to tea/polling
|
||||
|
|
@ -743,7 +742,7 @@ projects:
|
|||
path: ${tempDir.path}
|
||||
''');
|
||||
|
||||
// And the project omits issueAssistant.eventSource.type.
|
||||
// And the project omits issueTracker.eventSource.type.
|
||||
|
||||
// When loading the app config from disk.
|
||||
final config = await AppConfig.load(configFile.path);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,81 @@
|
|||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:code_work_spawner/code_work_spawner.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import '../test_support.dart';
|
||||
|
||||
void expectEventSourceUnderIssueTrackerBlock(String yaml) {
|
||||
final lines = const LineSplitter().convert(yaml);
|
||||
final issueTrackerIndex = lines.indexWhere(
|
||||
(line) => RegExp(r'^\s*issueTracker:\s*$').hasMatch(line),
|
||||
);
|
||||
expect(
|
||||
issueTrackerIndex,
|
||||
isNonNegative,
|
||||
reason: 'Expected an issueTracker block in the emitted config.',
|
||||
);
|
||||
|
||||
final issueTrackerIndent = _leadingSpaces(lines[issueTrackerIndex]);
|
||||
var foundNestedEventSource = false;
|
||||
|
||||
for (var index = issueTrackerIndex + 1; index < lines.length; index++) {
|
||||
final line = lines[index];
|
||||
if (line.trim().isEmpty) {
|
||||
continue;
|
||||
}
|
||||
final indent = _leadingSpaces(line);
|
||||
if (indent <= issueTrackerIndent) {
|
||||
break;
|
||||
}
|
||||
if (RegExp(r'^\s*eventSource:\s*$').hasMatch(line)) {
|
||||
foundNestedEventSource = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
foundNestedEventSource,
|
||||
isTrue,
|
||||
reason: 'Expected eventSource to be nested under issueTracker.',
|
||||
);
|
||||
}
|
||||
|
||||
int _leadingSpaces(String value) => value.length - value.trimLeft().length;
|
||||
|
||||
Map<String, dynamic> parseYamlToMap(String yaml) {
|
||||
final decoded = loadYaml(yaml);
|
||||
if (decoded is! YamlMap) {
|
||||
throw const FormatException('Expected YAML root map.');
|
||||
}
|
||||
return _normalizeYamlNode(decoded) as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
Object? _normalizeYamlNode(Object? value) {
|
||||
if (value is YamlMap) {
|
||||
return value.map(
|
||||
(key, dynamicValue) =>
|
||||
MapEntry(key.toString(), _normalizeYamlNode(dynamicValue)),
|
||||
);
|
||||
}
|
||||
if (value is YamlList) {
|
||||
return value.map(_normalizeYamlNode).toList(growable: false);
|
||||
}
|
||||
if (value is Map) {
|
||||
return value.map(
|
||||
(key, dynamicValue) =>
|
||||
MapEntry(key.toString(), _normalizeYamlNode(dynamicValue)),
|
||||
);
|
||||
}
|
||||
if (value is List) {
|
||||
return value.map(_normalizeYamlNode).toList(growable: false);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void main() {
|
||||
/// ```gherkin
|
||||
/// Feature: Init-config CLI
|
||||
|
|
@ -63,9 +133,20 @@ void main() {
|
|||
expect(result.stdout, contains('# - type: desktop'));
|
||||
expect(result.stdout, contains('issueTracker:'));
|
||||
expect(result.stdout, contains('provider: github'));
|
||||
expectEventSourceUnderIssueTrackerBlock(result.stdout);
|
||||
expect(result.stdout, contains('scm:'));
|
||||
expect(result.stdout, contains('projects:'));
|
||||
|
||||
final root = parseYamlToMap(result.stdout);
|
||||
final project =
|
||||
(root['projects'] as Map<String, dynamic>)['sample']
|
||||
as Map<String, dynamic>;
|
||||
final issueTracker = project['issueTracker'] as Map<String, dynamic>;
|
||||
expect(issueTracker['eventSource'], isA<Map<String, dynamic>>());
|
||||
final defaults = root['defaults'] as Map<String, dynamic>;
|
||||
final issueAssistant = defaults['issueAssistant'] as Map<String, dynamic>;
|
||||
expect(issueAssistant.containsKey('eventSource'), isFalse);
|
||||
|
||||
// And the printed config is valid when written to disk and loaded.
|
||||
await configFile.writeAsString(result.stdout);
|
||||
final config = await AppConfig.load(configFile.path);
|
||||
|
|
@ -112,9 +193,20 @@ void main() {
|
|||
expect(contents, contains('defaults:'));
|
||||
expect(contents, contains('issueTracker:'));
|
||||
expect(contents, contains('provider: github'));
|
||||
expectEventSourceUnderIssueTrackerBlock(contents);
|
||||
expect(contents, contains('# maxResponsesAfterHuman: 1'));
|
||||
expect(contents, contains('scm:'));
|
||||
expect(contents, contains('projects:'));
|
||||
|
||||
final root = parseYamlToMap(contents);
|
||||
final project =
|
||||
(root['projects'] as Map<String, dynamic>)['sample']
|
||||
as Map<String, dynamic>;
|
||||
final issueTracker = project['issueTracker'] as Map<String, dynamic>;
|
||||
expect(issueTracker['eventSource'], isA<Map<String, dynamic>>());
|
||||
final defaults = root['defaults'] as Map<String, dynamic>;
|
||||
final issueAssistant = defaults['issueAssistant'] as Map<String, dynamic>;
|
||||
expect(issueAssistant.containsKey('eventSource'), isFalse);
|
||||
final config = await AppConfig.load(outputFile.path);
|
||||
expect(config.projects['sample'], isNotNull);
|
||||
expect(config.defaults.maxResponsesAfterHuman, 1);
|
||||
|
|
|
|||
|
|
@ -129,7 +129,6 @@ void registerIssueAssistantAppRunOnceConcurrencyTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
maxConcurrentIssues: 3
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
|
|
@ -137,6 +136,9 @@ defaults:
|
|||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -267,13 +269,15 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ void registerIssueAssistantAppRunOnceCoreTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -92,6 +91,9 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
defaultBranch: main
|
||||
|
|
@ -192,13 +194,15 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -286,13 +290,15 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -401,7 +407,6 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
maxResponsesAfterHuman: 1
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
|
|
@ -409,6 +414,9 @@ defaults:
|
|||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -500,13 +508,15 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
|
|||
|
|
@ -151,16 +151,21 @@ void registerIssueAssistantAppRunOnceMultiProjectTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 30s
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
repoOne:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 30s
|
||||
repo: owner/repo-one
|
||||
path: ${repoOneDir.path}
|
||||
repoTwo:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 30s
|
||||
repo: owner/repo-two
|
||||
path: ${repoTwoDir.path}
|
||||
''');
|
||||
|
|
@ -288,7 +293,6 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -296,6 +300,9 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
provider: gitea
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
|
|
@ -378,7 +385,6 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -387,6 +393,8 @@ defaults:
|
|||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
provider: openproject
|
||||
scm:
|
||||
provider: github
|
||||
|
|
|
|||
|
|
@ -72,9 +72,11 @@ void registerIssueAssistantAppRunRetryTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 1s
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 1s
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ void registerIssueAssistantAppRunGitHubGosmeeTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -108,11 +107,13 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: github
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
type: gh/gosmee
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: gh/gosmee
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ void registerIssueAssistantAppRunGitLabGosmeeTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -122,11 +121,13 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: gitlab
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
type: glab/gosmee
|
||||
repo: group/subgroup/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: glab/gosmee
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
|
|||
|
|
@ -142,7 +142,6 @@ exit 1
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -150,11 +149,13 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: gitea
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
type: tea/gosmee
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: tea/gosmee
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
@ -357,13 +358,14 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: gitea
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: tea/gosmee
|
||||
eventSource:
|
||||
type: tea/gosmee
|
||||
reconciliation: continuous
|
||||
reconcileInterval: 1s
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
|
|||
|
|
@ -89,11 +89,12 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: github
|
||||
eventSource:
|
||||
type: gh/webhook-forward
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: gh/webhook-forward
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
@ -188,11 +189,12 @@ defaults:
|
|||
enabled: true
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: github
|
||||
eventSource:
|
||||
type: gh/webhook-forward
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: gh/webhook-forward
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
@ -368,13 +370,14 @@ defaults:
|
|||
timeout: 1m
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
provider: github
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
issueAssistant:
|
||||
eventSource: gh/webhook-forward
|
||||
eventSource:
|
||||
type: gh/webhook-forward
|
||||
reconciliation: continuous
|
||||
reconcileInterval: 1s
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
final app = await IssueAssistantApp.open(
|
||||
config: await AppConfig.load(configFile.path),
|
||||
|
|
|
|||
|
|
@ -104,13 +104,15 @@ void registerIssueAssistantAppRunOnceNotificationTests() {
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -228,7 +230,6 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
|
|
@ -241,6 +242,9 @@ defaults:
|
|||
username: code-work-spawner
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import '../../bin/code_work_spawner.dart' as _cliEntry;
|
||||
import '../../bin/code_work_spawner.dart' as cli_entry;
|
||||
|
||||
/// Result of a [runCli] invocation.
|
||||
typedef CliResult = ({int exitCode, String stdout, String stderr});
|
||||
|
|
@ -18,7 +18,7 @@ Future<CliResult> runCli(List<String> args) async {
|
|||
exitCode = 0;
|
||||
try {
|
||||
await IOOverrides.runZoned<Future<void>>(
|
||||
() => _cliEntry.main(args),
|
||||
() => cli_entry.main(args),
|
||||
stdout: () => out,
|
||||
stderr: () => err,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -94,13 +94,15 @@ JSON
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -216,13 +218,15 @@ worktreeDir: ${worktreeRoot.path}
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
@ -311,13 +315,15 @@ projects:
|
|||
defaults:
|
||||
issueAssistant:
|
||||
enabled: true
|
||||
pollInterval: 5m
|
||||
mentionTriggers: ["@helper"]
|
||||
responders:
|
||||
- id: primary
|
||||
command: ${responderScript.path}
|
||||
projects:
|
||||
sample:
|
||||
issueTracker:
|
||||
eventSource:
|
||||
pollInterval: 5m
|
||||
repo: owner/sample
|
||||
path: ${repoDir.path}
|
||||
''');
|
||||
|
|
|
|||
Loading…
Reference in New Issue