opencode-pilot 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +8 -1
- package/.releaserc.cjs +10 -1
- package/AGENTS.md +6 -12
- package/README.md +31 -25
- package/bin/opencode-pilot +47 -209
- package/examples/config.yaml +2 -9
- package/package.json +6 -6
- package/plugin/index.js +45 -245
- package/service/{io.opencode.ntfy.plist → io.opencode.pilot.plist} +5 -5
- package/service/server.js +44 -1381
- package/test/run_tests.bash +1 -1
- package/test/test_actions.bash +21 -36
- package/test/test_cli.bash +20 -24
- package/test/test_plist.bash +11 -12
- package/test/test_poller.bash +20 -20
- package/test/test_repo_config.bash +19 -233
- package/test/test_service.bash +48 -1095
- package/test/unit/paths.test.js +16 -43
- package/test/unit/plugin.test.js +46 -0
- package/dist/opencode-ntfy.tar.gz +0 -0
- package/plugin/config.js +0 -76
- package/plugin/logger.js +0 -125
- package/plugin/notifier.js +0 -110
- package/test/test_config.bash +0 -438
- package/test/test_logger.bash +0 -401
- package/test/test_notifier.bash +0 -310
- package/test/test_plugin.bash +0 -952
- package/test/unit/config.test.js +0 -86
package/test/run_tests.bash
CHANGED
|
@@ -8,7 +8,7 @@ set -euo pipefail
|
|
|
8
8
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
9
|
|
|
10
10
|
echo "========================================"
|
|
11
|
-
echo " opencode-
|
|
11
|
+
echo " opencode-pilot test suite"
|
|
12
12
|
echo "========================================"
|
|
13
13
|
echo ""
|
|
14
14
|
|
package/test/test_actions.bash
CHANGED
|
@@ -62,7 +62,7 @@ test_actions_uses_opencode_run() {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
test_actions_prompt_template() {
|
|
65
|
-
grep -q "prompt_template\|promptTemplate" "$SERVICE_DIR/actions.js" || {
|
|
65
|
+
grep -q "prompt_template\|promptTemplate\|buildPromptFromTemplate" "$SERVICE_DIR/actions.js" || {
|
|
66
66
|
echo "Prompt template support not found"
|
|
67
67
|
return 1
|
|
68
68
|
}
|
|
@@ -104,7 +104,7 @@ test_actions_build_local_command() {
|
|
|
104
104
|
|
|
105
105
|
const config = {
|
|
106
106
|
repo_path: '~/code/myrepo',
|
|
107
|
-
session: {
|
|
107
|
+
session: { name: 'issue-{number}' }
|
|
108
108
|
};
|
|
109
109
|
|
|
110
110
|
const cmd = buildCommand(item, config);
|
|
@@ -130,7 +130,7 @@ test_actions_build_local_command() {
|
|
|
130
130
|
fi
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
test_actions_session_name_template() {
|
|
134
134
|
if ! command -v node &>/dev/null; then
|
|
135
135
|
echo "SKIP: node not available"
|
|
136
136
|
return 0
|
|
@@ -138,33 +138,19 @@ test_actions_prompt_template_expansion() {
|
|
|
138
138
|
|
|
139
139
|
local result
|
|
140
140
|
result=$(node --experimental-vm-modules -e "
|
|
141
|
-
import {
|
|
141
|
+
import { buildSessionName } from './service/actions.js';
|
|
142
142
|
|
|
143
143
|
const item = {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
// Config with custom prompt template (e.g., for devcontainer)
|
|
150
|
-
const config = {
|
|
151
|
-
repo_path: '~/code/myrepo',
|
|
152
|
-
session: {
|
|
153
|
-
name_template: 'issue-{number}',
|
|
154
|
-
prompt_template: '/devcontainer issue-{number}\n\n{title}\n\n{body}'
|
|
155
|
-
}
|
|
144
|
+
number: 42,
|
|
145
|
+
repo_key: 'myorg/backend',
|
|
146
|
+
repo_short: 'backend'
|
|
156
147
|
};
|
|
157
148
|
|
|
158
|
-
const
|
|
149
|
+
const template = 'issue-{repo_short}-{number}';
|
|
150
|
+
const name = buildSessionName(template, item);
|
|
159
151
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
console.log('FAIL: Command should include expanded prompt template');
|
|
163
|
-
console.log('Got: ' + cmd);
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
if (!cmd.includes('Fix bug')) {
|
|
167
|
-
console.log('FAIL: Command should include title from template');
|
|
152
|
+
if (name !== 'issue-backend-42') {
|
|
153
|
+
console.log('FAIL: Expected issue-backend-42, got ' + name);
|
|
168
154
|
process.exit(1);
|
|
169
155
|
}
|
|
170
156
|
console.log('PASS');
|
|
@@ -179,7 +165,7 @@ test_actions_prompt_template_expansion() {
|
|
|
179
165
|
fi
|
|
180
166
|
}
|
|
181
167
|
|
|
182
|
-
|
|
168
|
+
test_actions_expand_template() {
|
|
183
169
|
if ! command -v node &>/dev/null; then
|
|
184
170
|
echo "SKIP: node not available"
|
|
185
171
|
return 0
|
|
@@ -187,19 +173,18 @@ test_actions_session_name_template() {
|
|
|
187
173
|
|
|
188
174
|
local result
|
|
189
175
|
result=$(node --experimental-vm-modules -e "
|
|
190
|
-
import {
|
|
176
|
+
import { expandTemplate } from './service/actions.js';
|
|
191
177
|
|
|
192
178
|
const item = {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
repo_short: 'backend'
|
|
179
|
+
title: 'Fix bug',
|
|
180
|
+
number: 456
|
|
196
181
|
};
|
|
197
182
|
|
|
198
|
-
const template = '
|
|
199
|
-
const
|
|
183
|
+
const template = 'Issue #{number}: {title}';
|
|
184
|
+
const expanded = expandTemplate(template, item);
|
|
200
185
|
|
|
201
|
-
if (
|
|
202
|
-
console.log('FAIL: Expected
|
|
186
|
+
if (expanded !== 'Issue #456: Fix bug') {
|
|
187
|
+
console.log('FAIL: Expected \"Issue #456: Fix bug\", got \"' + expanded + '\"');
|
|
203
188
|
process.exit(1);
|
|
204
189
|
}
|
|
205
190
|
console.log('PASS');
|
|
@@ -254,8 +239,8 @@ echo "Functional Tests:"
|
|
|
254
239
|
|
|
255
240
|
for test_func in \
|
|
256
241
|
test_actions_build_local_command \
|
|
257
|
-
|
|
258
|
-
|
|
242
|
+
test_actions_session_name_template \
|
|
243
|
+
test_actions_expand_template
|
|
259
244
|
do
|
|
260
245
|
run_test "${test_func#test_}" "$test_func"
|
|
261
246
|
done
|
package/test/test_cli.bash
CHANGED
|
@@ -51,9 +51,9 @@ test_cli_help_shows_usage() {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
"$CLI_PATH" help 2>&1 | grep -q "
|
|
56
|
-
echo "help command should show
|
|
54
|
+
test_cli_help_shows_start_command() {
|
|
55
|
+
"$CLI_PATH" help 2>&1 | grep -q "start" || {
|
|
56
|
+
echo "help command should show start command"
|
|
57
57
|
return 1
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -65,6 +65,13 @@ test_cli_help_shows_status_command() {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
test_cli_help_shows_config_command() {
|
|
69
|
+
"$CLI_PATH" help 2>&1 | grep -q "config" || {
|
|
70
|
+
echo "help command should show config command"
|
|
71
|
+
return 1
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
test_cli_default_shows_help() {
|
|
69
76
|
"$CLI_PATH" 2>&1 | grep -q "Usage:" || {
|
|
70
77
|
echo "default should show usage"
|
|
@@ -87,34 +94,23 @@ test_cli_unknown_command_shows_error() {
|
|
|
87
94
|
# Status Command Tests
|
|
88
95
|
# =============================================================================
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
local output
|
|
92
|
-
output=$("$CLI_PATH" status 2>&1) || true
|
|
93
|
-
|
|
94
|
-
echo "$output" | grep -qi "plugin" || {
|
|
95
|
-
echo "status should show plugin info"
|
|
96
|
-
echo "Output: $output"
|
|
97
|
-
return 1
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
test_cli_status_shows_notification_config() {
|
|
97
|
+
test_cli_status_shows_service_info() {
|
|
102
98
|
local output
|
|
103
99
|
output=$("$CLI_PATH" status 2>&1) || true
|
|
104
100
|
|
|
105
|
-
echo "$output" | grep -qi "
|
|
106
|
-
echo "status should show
|
|
101
|
+
echo "$output" | grep -qi "service" || {
|
|
102
|
+
echo "status should show service info"
|
|
107
103
|
echo "Output: $output"
|
|
108
104
|
return 1
|
|
109
105
|
}
|
|
110
106
|
}
|
|
111
107
|
|
|
112
|
-
|
|
108
|
+
test_cli_status_shows_config_info() {
|
|
113
109
|
local output
|
|
114
110
|
output=$("$CLI_PATH" status 2>&1) || true
|
|
115
111
|
|
|
116
|
-
echo "$output" | grep -qi "
|
|
117
|
-
echo "status should show
|
|
112
|
+
echo "$output" | grep -qi "config" || {
|
|
113
|
+
echo "status should show config info"
|
|
118
114
|
echo "Output: $output"
|
|
119
115
|
return 1
|
|
120
116
|
}
|
|
@@ -139,8 +135,9 @@ echo "Help Command Tests:"
|
|
|
139
135
|
|
|
140
136
|
for test_func in \
|
|
141
137
|
test_cli_help_shows_usage \
|
|
142
|
-
|
|
138
|
+
test_cli_help_shows_start_command \
|
|
143
139
|
test_cli_help_shows_status_command \
|
|
140
|
+
test_cli_help_shows_config_command \
|
|
144
141
|
test_cli_default_shows_help \
|
|
145
142
|
test_cli_unknown_command_shows_error
|
|
146
143
|
do
|
|
@@ -151,9 +148,8 @@ echo ""
|
|
|
151
148
|
echo "Status Command Tests:"
|
|
152
149
|
|
|
153
150
|
for test_func in \
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
test_cli_status_shows_polling_config
|
|
151
|
+
test_cli_status_shows_service_info \
|
|
152
|
+
test_cli_status_shows_config_info
|
|
157
153
|
do
|
|
158
154
|
run_test "${test_func#test_}" "$test_func"
|
|
159
155
|
done
|
package/test/test_plist.bash
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
#
|
|
3
|
-
# Tests for service/io.opencode.
|
|
4
|
-
# Issue #13: Separate callback server as brew service
|
|
3
|
+
# Tests for service/io.opencode.pilot.plist - LaunchAgent plist for brew services
|
|
5
4
|
#
|
|
6
5
|
|
|
7
6
|
set -euo pipefail
|
|
@@ -19,7 +18,7 @@ echo ""
|
|
|
19
18
|
# =============================================================================
|
|
20
19
|
|
|
21
20
|
test_plist_file_exists() {
|
|
22
|
-
assert_file_exists "$SERVICE_DIR/io.opencode.
|
|
21
|
+
assert_file_exists "$SERVICE_DIR/io.opencode.pilot.plist"
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
test_plist_is_valid_xml() {
|
|
@@ -27,7 +26,7 @@ test_plist_is_valid_xml() {
|
|
|
27
26
|
echo "SKIP: plutil not available (macOS only)"
|
|
28
27
|
return 0
|
|
29
28
|
fi
|
|
30
|
-
plutil -lint "$SERVICE_DIR/io.opencode.
|
|
29
|
+
plutil -lint "$SERVICE_DIR/io.opencode.pilot.plist" 2>&1 || {
|
|
31
30
|
echo "plist is not valid XML"
|
|
32
31
|
return 1
|
|
33
32
|
}
|
|
@@ -38,56 +37,56 @@ test_plist_is_valid_xml() {
|
|
|
38
37
|
# =============================================================================
|
|
39
38
|
|
|
40
39
|
test_plist_has_label() {
|
|
41
|
-
grep -q "<string>io.opencode.
|
|
40
|
+
grep -q "<string>io.opencode.pilot</string>" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
42
41
|
echo "Label not found in plist"
|
|
43
42
|
return 1
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
test_plist_has_program_arguments() {
|
|
48
|
-
grep -q "<key>ProgramArguments</key>" "$SERVICE_DIR/io.opencode.
|
|
47
|
+
grep -q "<key>ProgramArguments</key>" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
49
48
|
echo "ProgramArguments not found in plist"
|
|
50
49
|
return 1
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
test_plist_runs_node() {
|
|
55
|
-
grep -q "node" "$SERVICE_DIR/io.opencode.
|
|
54
|
+
grep -q "node" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
56
55
|
echo "node command not found in plist"
|
|
57
56
|
return 1
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
test_plist_runs_server_js() {
|
|
62
|
-
grep -q "server.js" "$SERVICE_DIR/io.opencode.
|
|
61
|
+
grep -q "server.js" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
63
62
|
echo "server.js not found in plist"
|
|
64
63
|
return 1
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
test_plist_has_keep_alive() {
|
|
69
|
-
grep -q "<key>KeepAlive</key>" "$SERVICE_DIR/io.opencode.
|
|
68
|
+
grep -q "<key>KeepAlive</key>" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
70
69
|
echo "KeepAlive not found in plist"
|
|
71
70
|
return 1
|
|
72
71
|
}
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
test_plist_has_run_at_load() {
|
|
76
|
-
grep -q "<key>RunAtLoad</key>" "$SERVICE_DIR/io.opencode.
|
|
75
|
+
grep -q "<key>RunAtLoad</key>" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
77
76
|
echo "RunAtLoad not found in plist"
|
|
78
77
|
return 1
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
test_plist_has_stdout_log() {
|
|
83
|
-
grep -q "stdout\|StandardOutPath" "$SERVICE_DIR/io.opencode.
|
|
82
|
+
grep -q "stdout\|StandardOutPath" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
84
83
|
echo "Stdout logging not found in plist"
|
|
85
84
|
return 1
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
test_plist_has_stderr_log() {
|
|
90
|
-
grep -q "stderr\|StandardErrorPath" "$SERVICE_DIR/io.opencode.
|
|
89
|
+
grep -q "stderr\|StandardErrorPath" "$SERVICE_DIR/io.opencode.pilot.plist" || {
|
|
91
90
|
echo "Stderr logging not found in plist"
|
|
92
91
|
return 1
|
|
93
92
|
}
|
package/test/test_poller.bash
CHANGED
|
@@ -43,30 +43,23 @@ test_poller_exports_create_poller() {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
grep -q "export.*function
|
|
48
|
-
echo "
|
|
46
|
+
test_poller_exports_poll_generic_source() {
|
|
47
|
+
grep -q "export.*function pollGenericSource\|export.*pollGenericSource" "$SERVICE_DIR/poller.js" || {
|
|
48
|
+
echo "pollGenericSource export not found in poller.js"
|
|
49
49
|
return 1
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
test_poller_supports_github_issues() {
|
|
58
|
-
grep -q "github_issue\|github-issue" "$SERVICE_DIR/poller.js" || {
|
|
59
|
-
echo "GitHub issue source type not found in poller.js"
|
|
53
|
+
test_poller_exports_apply_mappings() {
|
|
54
|
+
grep -q "export.*function applyMappings\|export.*applyMappings" "$SERVICE_DIR/poller.js" || {
|
|
55
|
+
echo "applyMappings export not found in poller.js"
|
|
60
56
|
return 1
|
|
61
57
|
}
|
|
62
58
|
}
|
|
63
59
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return 1
|
|
68
|
-
}
|
|
69
|
-
}
|
|
60
|
+
# =============================================================================
|
|
61
|
+
# Implementation Tests
|
|
62
|
+
# =============================================================================
|
|
70
63
|
|
|
71
64
|
test_poller_uses_mcp_client() {
|
|
72
65
|
grep -q "@modelcontextprotocol/sdk" "$SERVICE_DIR/poller.js" || {
|
|
@@ -82,6 +75,13 @@ test_poller_tracks_processed_items() {
|
|
|
82
75
|
}
|
|
83
76
|
}
|
|
84
77
|
|
|
78
|
+
test_poller_supports_generic_tools() {
|
|
79
|
+
grep -q "tool" "$SERVICE_DIR/poller.js" || {
|
|
80
|
+
echo "Tool-based polling not found in poller.js"
|
|
81
|
+
return 1
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
85
|
# =============================================================================
|
|
86
86
|
# Run Tests
|
|
87
87
|
# =============================================================================
|
|
@@ -100,7 +100,8 @@ echo "Export Tests:"
|
|
|
100
100
|
|
|
101
101
|
for test_func in \
|
|
102
102
|
test_poller_exports_create_poller \
|
|
103
|
-
|
|
103
|
+
test_poller_exports_poll_generic_source \
|
|
104
|
+
test_poller_exports_apply_mappings
|
|
104
105
|
do
|
|
105
106
|
run_test "${test_func#test_}" "$test_func"
|
|
106
107
|
done
|
|
@@ -109,10 +110,9 @@ echo ""
|
|
|
109
110
|
echo "Implementation Tests:"
|
|
110
111
|
|
|
111
112
|
for test_func in \
|
|
112
|
-
test_poller_supports_github_issues \
|
|
113
|
-
test_poller_supports_linear_issues \
|
|
114
113
|
test_poller_uses_mcp_client \
|
|
115
|
-
test_poller_tracks_processed_items
|
|
114
|
+
test_poller_tracks_processed_items \
|
|
115
|
+
test_poller_supports_generic_tools
|
|
116
116
|
do
|
|
117
117
|
run_test "${test_func#test_}" "$test_func"
|
|
118
118
|
done
|
|
@@ -68,23 +68,16 @@ test_repo_config_supports_yaml() {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
grep -q "
|
|
73
|
-
echo "
|
|
71
|
+
test_repo_config_supports_source_config() {
|
|
72
|
+
grep -q "sources" "$SERVICE_DIR/repo-config.js" || {
|
|
73
|
+
echo "Sources support not found"
|
|
74
74
|
return 1
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
grep -q "
|
|
80
|
-
echo "
|
|
81
|
-
return 1
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
test_repo_config_expands_placeholders() {
|
|
86
|
-
grep -q "{repo}\|placeholder" "$SERVICE_DIR/repo-config.js" || {
|
|
87
|
-
echo "Placeholder expansion not found"
|
|
78
|
+
test_repo_config_supports_tool_mappings() {
|
|
79
|
+
grep -q "mappings\|tools" "$SERVICE_DIR/repo-config.js" || {
|
|
80
|
+
echo "Tool mappings support not found"
|
|
88
81
|
return 1
|
|
89
82
|
}
|
|
90
83
|
}
|
|
@@ -93,7 +86,7 @@ test_repo_config_expands_placeholders() {
|
|
|
93
86
|
# Functional Tests
|
|
94
87
|
# =============================================================================
|
|
95
88
|
|
|
96
|
-
|
|
89
|
+
test_repo_config_returns_empty_for_unknown_repo() {
|
|
97
90
|
if ! command -v node &>/dev/null; then
|
|
98
91
|
echo "SKIP: node not available"
|
|
99
92
|
return 0
|
|
@@ -103,15 +96,11 @@ test_repo_config_defaults() {
|
|
|
103
96
|
result=$(node --experimental-vm-modules -e "
|
|
104
97
|
import { getRepoConfig } from './service/repo-config.js';
|
|
105
98
|
|
|
106
|
-
// Get config for non-existent repo should return
|
|
99
|
+
// Get config for non-existent repo should return empty object
|
|
107
100
|
const config = getRepoConfig('nonexistent/repo');
|
|
108
101
|
|
|
109
|
-
if (
|
|
110
|
-
console.log('FAIL:
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
if (!config.readiness.labels) {
|
|
114
|
-
console.log('FAIL: Missing readiness.labels in defaults');
|
|
102
|
+
if (typeof config !== 'object') {
|
|
103
|
+
console.log('FAIL: Expected object for unknown repo');
|
|
115
104
|
process.exit(1);
|
|
116
105
|
}
|
|
117
106
|
console.log('PASS');
|
|
@@ -126,7 +115,7 @@ test_repo_config_defaults() {
|
|
|
126
115
|
fi
|
|
127
116
|
}
|
|
128
117
|
|
|
129
|
-
|
|
118
|
+
test_repo_config_gets_sources() {
|
|
130
119
|
if ! command -v node &>/dev/null; then
|
|
131
120
|
echo "SKIP: node not available"
|
|
132
121
|
return 0
|
|
@@ -134,206 +123,15 @@ test_repo_config_prefix_matching() {
|
|
|
134
123
|
|
|
135
124
|
local result
|
|
136
125
|
result=$(node --experimental-vm-modules -e "
|
|
137
|
-
import {
|
|
138
|
-
|
|
139
|
-
// Load test config
|
|
140
|
-
const testConfig = {
|
|
141
|
-
repos: {
|
|
142
|
-
'myorg/': {
|
|
143
|
-
repo_path: '~/code/{repo}',
|
|
144
|
-
readiness: { labels: { any_of: ['ready'] } }
|
|
145
|
-
},
|
|
146
|
-
'myorg/backend': {
|
|
147
|
-
readiness: { labels: { any_of: ['backend-ready'] } }
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
loadRepoConfig(testConfig);
|
|
126
|
+
import { getAllSources } from './service/repo-config.js';
|
|
153
127
|
|
|
154
|
-
//
|
|
155
|
-
const config = getRepoConfig('myorg/backend');
|
|
156
|
-
|
|
157
|
-
// Should have readiness from exact match
|
|
158
|
-
if (!config.readiness.labels.any_of.includes('backend-ready')) {
|
|
159
|
-
console.log('FAIL: Expected any_of to include backend-ready from exact match');
|
|
160
|
-
process.exit(1);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Get config for myorg/frontend - should get prefix config
|
|
164
|
-
const frontendConfig = getRepoConfig('myorg/frontend');
|
|
165
|
-
if (!frontendConfig.readiness.labels.any_of.includes('ready')) {
|
|
166
|
-
console.log('FAIL: Expected any_of to include ready from prefix');
|
|
167
|
-
process.exit(1);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// repo_path should have {repo} expanded
|
|
171
|
-
if (frontendConfig.repo_path !== '~/code/frontend') {
|
|
172
|
-
console.log('FAIL: Expected expanded repo_path, got ' + frontendConfig.repo_path);
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
console.log('PASS');
|
|
177
|
-
" 2>&1) || {
|
|
178
|
-
echo "Functional test failed: $result"
|
|
179
|
-
return 1
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if ! echo "$result" | grep -q "PASS"; then
|
|
183
|
-
echo "$result"
|
|
184
|
-
return 1
|
|
185
|
-
fi
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
# =============================================================================
|
|
189
|
-
# Default Sources Tests
|
|
190
|
-
# =============================================================================
|
|
191
|
-
|
|
192
|
-
test_repo_config_default_sources() {
|
|
193
|
-
if ! command -v node &>/dev/null; then
|
|
194
|
-
echo "SKIP: node not available"
|
|
195
|
-
return 0
|
|
196
|
-
fi
|
|
197
|
-
|
|
198
|
-
local result
|
|
199
|
-
result=$(node --experimental-vm-modules -e "
|
|
200
|
-
import { loadRepoConfig, getRepoConfig, getAllSources } from './service/repo-config.js';
|
|
201
|
-
|
|
202
|
-
// Load config with repo that has no sources specified
|
|
203
|
-
const testConfig = {
|
|
204
|
-
repos: {
|
|
205
|
-
'myorg/': {
|
|
206
|
-
repo_path: '~/code/{repo}'
|
|
207
|
-
},
|
|
208
|
-
'myorg/backend': {} // No sources specified
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
loadRepoConfig(testConfig);
|
|
213
|
-
|
|
214
|
-
// Get config - should have default github_issue source
|
|
215
|
-
const config = getRepoConfig('myorg/backend');
|
|
216
|
-
|
|
217
|
-
if (!config.sources || config.sources.length === 0) {
|
|
218
|
-
console.log('FAIL: Expected default sources, got empty array');
|
|
219
|
-
process.exit(1);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const defaultSource = config.sources[0];
|
|
223
|
-
if (defaultSource.type !== 'github_issue') {
|
|
224
|
-
console.log('FAIL: Expected default source type github_issue, got ' + defaultSource.type);
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (!defaultSource.fetch || defaultSource.fetch.assignee !== '@me') {
|
|
229
|
-
console.log('FAIL: Expected default fetch.assignee=@me, got ' + JSON.stringify(defaultSource.fetch));
|
|
230
|
-
process.exit(1);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (!defaultSource.fetch || defaultSource.fetch.state !== 'open') {
|
|
234
|
-
console.log('FAIL: Expected default fetch.state=open, got ' + JSON.stringify(defaultSource.fetch));
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
console.log('PASS');
|
|
239
|
-
" 2>&1) || {
|
|
240
|
-
echo "Functional test failed: $result"
|
|
241
|
-
return 1
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if ! echo "$result" | grep -q "PASS"; then
|
|
245
|
-
echo "$result"
|
|
246
|
-
return 1
|
|
247
|
-
fi
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
test_repo_config_explicit_sources_override_defaults() {
|
|
251
|
-
if ! command -v node &>/dev/null; then
|
|
252
|
-
echo "SKIP: node not available"
|
|
253
|
-
return 0
|
|
254
|
-
fi
|
|
255
|
-
|
|
256
|
-
local result
|
|
257
|
-
result=$(node --experimental-vm-modules -e "
|
|
258
|
-
import { loadRepoConfig, getRepoConfig } from './service/repo-config.js';
|
|
259
|
-
|
|
260
|
-
// Load config with explicit sources
|
|
261
|
-
const testConfig = {
|
|
262
|
-
repos: {
|
|
263
|
-
'myorg/backend': {
|
|
264
|
-
sources: [
|
|
265
|
-
{ type: 'github_pr', fetch: { state: 'open' } }
|
|
266
|
-
]
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
loadRepoConfig(testConfig);
|
|
272
|
-
|
|
273
|
-
// Get config - should have explicit sources, not defaults
|
|
274
|
-
const config = getRepoConfig('myorg/backend');
|
|
275
|
-
|
|
276
|
-
if (config.sources.length !== 1) {
|
|
277
|
-
console.log('FAIL: Expected 1 source, got ' + config.sources.length);
|
|
278
|
-
process.exit(1);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (config.sources[0].type !== 'github_pr') {
|
|
282
|
-
console.log('FAIL: Expected explicit github_pr source, got ' + config.sources[0].type);
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
console.log('PASS');
|
|
287
|
-
" 2>&1) || {
|
|
288
|
-
echo "Functional test failed: $result"
|
|
289
|
-
return 1
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if ! echo "$result" | grep -q "PASS"; then
|
|
293
|
-
echo "$result"
|
|
294
|
-
return 1
|
|
295
|
-
fi
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
test_repo_config_get_all_sources_includes_defaults() {
|
|
299
|
-
if ! command -v node &>/dev/null; then
|
|
300
|
-
echo "SKIP: node not available"
|
|
301
|
-
return 0
|
|
302
|
-
fi
|
|
303
|
-
|
|
304
|
-
local result
|
|
305
|
-
result=$(node --experimental-vm-modules -e "
|
|
306
|
-
import { loadRepoConfig, getAllSources } from './service/repo-config.js';
|
|
307
|
-
|
|
308
|
-
// Load config with repo that has no sources specified
|
|
309
|
-
const testConfig = {
|
|
310
|
-
repos: {
|
|
311
|
-
'myorg/backend': {
|
|
312
|
-
repo_path: '~/code/backend'
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
loadRepoConfig(testConfig);
|
|
318
|
-
|
|
319
|
-
// getAllSources should include the default source
|
|
128
|
+
// getAllSources should return an array
|
|
320
129
|
const sources = getAllSources();
|
|
321
130
|
|
|
322
|
-
if (sources
|
|
323
|
-
console.log('FAIL: Expected
|
|
324
|
-
process.exit(1);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (sources[0].type !== 'github_issue') {
|
|
328
|
-
console.log('FAIL: Expected github_issue source, got ' + sources[0].type);
|
|
131
|
+
if (!Array.isArray(sources)) {
|
|
132
|
+
console.log('FAIL: Expected array from getAllSources');
|
|
329
133
|
process.exit(1);
|
|
330
134
|
}
|
|
331
|
-
|
|
332
|
-
if (sources[0].repo_key !== 'myorg/backend') {
|
|
333
|
-
console.log('FAIL: Expected repo_key myorg/backend, got ' + sources[0].repo_key);
|
|
334
|
-
process.exit(1);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
135
|
console.log('PASS');
|
|
338
136
|
" 2>&1) || {
|
|
339
137
|
echo "Functional test failed: $result"
|
|
@@ -375,9 +173,8 @@ echo "Implementation Tests:"
|
|
|
375
173
|
|
|
376
174
|
for test_func in \
|
|
377
175
|
test_repo_config_supports_yaml \
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
test_repo_config_expands_placeholders
|
|
176
|
+
test_repo_config_supports_source_config \
|
|
177
|
+
test_repo_config_supports_tool_mappings
|
|
381
178
|
do
|
|
382
179
|
run_test "${test_func#test_}" "$test_func"
|
|
383
180
|
done
|
|
@@ -386,19 +183,8 @@ echo ""
|
|
|
386
183
|
echo "Functional Tests:"
|
|
387
184
|
|
|
388
185
|
for test_func in \
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
do
|
|
392
|
-
run_test "${test_func#test_}" "$test_func"
|
|
393
|
-
done
|
|
394
|
-
|
|
395
|
-
echo ""
|
|
396
|
-
echo "Default Sources Tests:"
|
|
397
|
-
|
|
398
|
-
for test_func in \
|
|
399
|
-
test_repo_config_default_sources \
|
|
400
|
-
test_repo_config_explicit_sources_override_defaults \
|
|
401
|
-
test_repo_config_get_all_sources_includes_defaults
|
|
186
|
+
test_repo_config_returns_empty_for_unknown_repo \
|
|
187
|
+
test_repo_config_gets_sources
|
|
402
188
|
do
|
|
403
189
|
run_test "${test_func#test_}" "$test_func"
|
|
404
190
|
done
|